X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=3094dd2f3ae37af22107b89228561f2002e5f99a;hp=324b6b81dabf7a55c2d5b9085717e9d949de8ae6;hb=0460bb60e03d87ed5c65071477c79cc7d2884db3;hpb=bd4e115a78b52e3fbc016e5e30bb0e19b2a9e7d6 diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 324b6b81d..3094dd2f3 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -6,7 +6,7 @@ // 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. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -42,6 +42,7 @@ #include "SMESH_Algo.hxx" #include "SMESH_ControlsDef.hxx" #include "SMESH_Group.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_OctreeNode.hxx" #include "SMESH_subMesh.hxx" @@ -49,6 +50,7 @@ #include #include "utilities.h" +#include "chrono.hxx" #include #include @@ -58,15 +60,10 @@ #include #include #include -#include #include -#include #include #include -#include #include -#include -#include #include #include #include @@ -97,6 +94,8 @@ #include #include +#include + #include #include @@ -105,10 +104,16 @@ using namespace std; using namespace SMESH::Controls; -typedef map > TElemOfNodeListMap; -typedef map > TElemOfElemListMap; - -typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator; +namespace +{ + template < class ELEM_SET > + SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements ) + { + typedef SMDS_SetIterator + < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator; + return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + } +} //======================================================================= //function : SMESH_MeshEditor @@ -120,6 +125,53 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) { } +//================================================================================ +/*! + * \brief Clears myLastCreatedNodes and myLastCreatedElems + */ +//================================================================================ + +void SMESH_MeshEditor::ClearLastCreated() +{ + myLastCreatedNodes.Clear(); + myLastCreatedElems.Clear(); +} + +//================================================================================ +/*! + * \brief Initializes members by an existing element + * \param [in] elem - the source element + * \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron + */ +//================================================================================ + +SMESH_MeshEditor::ElemFeatures& +SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly ) +{ + if ( elem ) + { + myType = elem->GetType(); + if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume ) + { + myIsPoly = elem->IsPoly(); + if ( myIsPoly ) + { + myIsQuad = elem->IsQuadratic(); + if ( myType == SMDSAbs_Volume && !basicOnly ) + { + vector quant = static_cast( elem )->GetQuantities(); + myPolyhedQuantities.swap( quant ); + } + } + } + else if ( myType == SMDSAbs_Ball && !basicOnly ) + { + myBallDiameter = static_cast(elem)->GetDiameter(); + } + } + return *this; +} + //======================================================================= /*! * \brief Add element @@ -128,18 +180,16 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & node, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID, - const double ballDiameter) + const ElemFeatures& features) { - //MESSAGE("AddElement " <= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID); else e = mesh->AddFace (node[0], node[1], node[2] ); @@ -154,6 +204,12 @@ SMESH_MeshEditor::AddElement(const vector & node, else e = mesh->AddFace (node[0], node[1], node[2], node[3], node[4], node[5] ); } + else if (nbnode == 7) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3], + node[4], node[5], node[6] ); + } else if (nbnode == 8) { if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7], ID); @@ -166,14 +222,21 @@ SMESH_MeshEditor::AddElement(const vector & node, else e = mesh->AddFace (node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7], node[8] ); } - } else { + } + else if ( !features.myIsQuad ) + { if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID); else e = mesh->AddPolygonalFace (node ); } + else if ( nbnode % 2 == 0 ) // just a protection + { + if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID); + else e = mesh->AddQuadPolygonalFace (node ); + } break; case SMDSAbs_Volume: - if ( !isPoly ) { + if ( !features.myIsPoly ) { if (nbnode == 4) { if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID); else e = mesh->AddVolume (node[0], node[1], node[2], node[3] ); @@ -261,6 +324,16 @@ SMESH_MeshEditor::AddElement(const vector & node, node[24],node[25],node[26] ); } } + else if ( !features.myIsQuad ) + { + if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID); + else e = mesh->AddPolyhedralVolume (node, features.myPolyhedQuantities ); + } + else + { + // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID); + // else e = mesh->AddQuadPolyhedralVolume (node, features.myPolyhedQuantities ); + } break; case SMDSAbs_Edge: @@ -283,12 +356,12 @@ SMESH_MeshEditor::AddElement(const vector & node, case SMDSAbs_Node: if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID); - else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z()); + else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z() ); break; case SMDSAbs_Ball: - if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID); - else e = mesh->AddBall (node[0], ballDiameter); + if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID); + else e = mesh->AddBall (node[0], features.myBallDiameter ); break; default:; @@ -303,10 +376,8 @@ SMESH_MeshEditor::AddElement(const vector & node, */ //======================================================================= -SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID) +SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs, + const ElemFeatures& features) { vector nodes; nodes.reserve( nodeIDs.size() ); @@ -317,7 +388,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs else return 0; } - return AddElement( nodes, type, isPoly, ID ); + return AddElement( nodes, features ); } //======================================================================= @@ -389,6 +460,53 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs, return removed; } +//================================================================================ +/*! + * \brief Create 0D elements on all nodes of the given object except those + * nodes on which a 0D element already exists. + * \param elements - Elements on whose nodes to create 0D elements; if empty, + * the all mesh is treated + * \param all0DElems - returns all 0D elements found or created on nodes of \a elements + */ +//================================================================================ + +void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements, + TIDSortedElemSet& all0DElems ) +{ + SMDS_ElemIteratorPtr elemIt; + vector< const SMDS_MeshElement* > allNodes; + if ( elements.empty() ) + { + allNodes.reserve( GetMeshDS()->NbNodes() ); + elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node ); + while ( elemIt->more() ) + allNodes.push_back( elemIt->next() ); + + elemIt = elemSetIterator( allNodes ); + } + else + { + elemIt = elemSetIterator( elements ); + } + + while ( elemIt->more() ) + { + const SMDS_MeshElement* e = elemIt->next(); + SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); + SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement ); + if ( it0D->more() ) + all0DElems.insert( it0D->next() ); + else { + myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n )); + all0DElems.insert( myLastCreatedElems.Last() ); + } + } + } +} + //======================================================================= //function : FindShape //purpose : Return an index of the shape theElem is on @@ -448,14 +566,12 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) } else { - const map& id2sm = GetMeshDS()->SubMeshes(); - map::const_iterator id_sm = id2sm.begin(); - for ( ; id_sm != id2sm.end(); ++id_sm ) - if ( id_sm->second->Contains( theElem )) - return id_sm->first; + SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes(); + while ( const SMESHDS_SubMesh* sm = smIt->next() ) + if ( sm->Contains( theElem )) + return sm->GetID(); } - //MESSAGE ("::FindShape() - SHAPE NOT FOUND") return 0; } @@ -477,12 +593,12 @@ bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node, } //======================================================================= -//function : ShiftNodesQuadTria -//purpose : auxilary -// Shift nodes in the array corresponded to quadratic triangle +//function : shiftNodesQuadTria +//purpose : 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[]) + +static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes) { const SMDS_MeshNode* nd1 = aNodes[0]; aNodes[0] = aNodes[1]; @@ -495,53 +611,42 @@ static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[]) } //======================================================================= -//function : edgeConnectivity -//purpose : auxilary -// return number of the edges connected with the theNode. +//function : nbEdgeConnectivity +//purpose : return number of the edges connected with the theNode. // if theEdges has connections with the other type of the -// elements, return -1 +// elements, return -1 //======================================================================= + static int nbEdgeConnectivity(const SMDS_MeshNode* theNode) { - SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(); - int nb=0; - while(elemIt->more()) { - elemIt->next(); - nb++; - } - return nb; + // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(); + // int nb=0; + // while(elemIt->more()) { + // elemIt->next(); + // nb++; + // } + // return nb; + return theNode->NbInverseElements(); } - //======================================================================= -//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) +//function : getNodesFromTwoTria +//purpose : //======================================================================= -static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1, + +static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1, const SMDS_MeshElement * theTria2, - const SMDS_MeshNode* N1[], - const SMDS_MeshNode* N2[]) + vector< const SMDS_MeshNode*>& N1, + vector< 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; + N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() ); + if ( N1.size() < 6 ) return false; + N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() ); + if ( N2.size() < 6 ) return false; int sames[3] = {-1,-1,-1}; int nbsames = 0; - int j; + int i, j; for(i=0; i<3; i++) { for(j=0; j<3; j++) { if(N1[i]==N2[j]) { @@ -553,18 +658,18 @@ static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1, } if(nbsames!=2) return false; if(sames[0]>-1) { - ShiftNodesQuadTria(N1); + shiftNodesQuadTria(N1); if(sames[1]>-1) { - ShiftNodesQuadTria(N1); + shiftNodesQuadTria(N1); } } i = sames[0] + sames[1] + sames[2]; for(; i<2; i++) { - ShiftNodesQuadTria(N2); + shiftNodesQuadTria(N2); } - // now we receive following N1 and N2 (using numeration as above image) + // now we receive following N1 and N2 (using numeration as in the image below) // 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 + // i.e. first nodes from both arrays form a new diagonal return true; } @@ -599,7 +704,7 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, // 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 sameInd [] = { -1, -1, -1, -1, -1, -1 }; int i = 0; SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); while ( it->more() ) { @@ -625,15 +730,15 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, } // find indices of 1,2 and of A,B in theTria1 - int iA = 0, iB = 0, i1 = 0, i2 = 0; + int iA = -1, iB = 0, i1 = 0, i2 = 0; for ( i = 0; i < 6; i++ ) { - if ( sameInd [ i ] == 0 ) { + if ( sameInd [ i ] == -1 ) { if ( i < 3 ) i1 = i; else i2 = i; } else if (i < 3) { - if ( iA ) iB = i; - else iA = i; + if ( iA >= 0) iB = i; + else iA = i; } } // nodes 1 and 2 should not be the same @@ -653,9 +758,11 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, } // end if(F1 && F2) // check case of quadratic faces - if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle) + if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle && + theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle) return false; - if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle) + if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&& + theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle) return false; // 5 @@ -668,32 +775,61 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, // 4 +--+--+ 3 // 8 - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2)) + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + 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 ); - + vector< const SMDS_MeshNode*> N1new( N1.size() ); + vector< const SMDS_MeshNode*> N2new( N2.size() ); + N1new.back() = N1.back(); // central node of biquadratic + N2new.back() = N2.back(); + N1new[0] = N1[0]; N2new[0] = N1[0]; + N1new[1] = N2[0]; N2new[1] = N1[1]; + N1new[2] = N2[1]; N2new[2] = N2[0]; + N1new[3] = N1[4]; N2new[3] = N1[3]; + N1new[4] = N2[3]; N2new[4] = N2[5]; + N1new[5] = N1[5]; N2new[5] = N1[4]; + // change nodes in faces + GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() ); + GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() ); + + // move the central node of biquadratic triangle + SMESH_MesherHelper helper( *GetMesh() ); + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + const SMDS_MeshElement* tria = is2nd ? theTria2 : theTria1; + vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new; + if ( nodes.size() < 7 ) + continue; + helper.SetSubShape( tria->getshapeId() ); + const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() ); + gp_Pnt xyz; + if ( F.IsNull() ) + { + xyz = ( SMESH_TNodeXYZ( nodes[3] ) + + SMESH_TNodeXYZ( nodes[4] ) + + SMESH_TNodeXYZ( nodes[5] )) / 3.; + } + else + { + bool checkUV; + gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) + + helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) + + helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.; + TopLoc_Location loc; + Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc); + xyz = S->Value( uv.X(), uv.Y() ); + xyz.Transform( loc ); + if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE && // set UV + nodes[6]->getshapeId() > 0 ) + GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() ); + } + GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() ); + } return true; } @@ -715,30 +851,28 @@ static bool findTriangles(const SMDS_MeshNode * theNode1, SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face); while (it->more()) { const SMDS_MeshElement* elem = it->next(); - if ( elem->NbNodes() == 3 ) + if ( elem->NbCornerNodes() == 3 ) emap.insert( elem ); } it = theNode2->GetInverseElementIterator(SMDSAbs_Face); while (it->more()) { const SMDS_MeshElement* elem = it->next(); - if ( emap.find( elem ) != emap.end() ) { - if ( theTria1 ) { - // theTria1 must be element with minimum ID - if( theTria1->GetID() < elem->GetID() ) { - theTria2 = elem; - } - else { - theTria2 = theTria1; - theTria1 = elem; - } - break; - } - else { + if ( emap.count( elem )) { + if ( !theTria1 ) + { theTria1 = elem; } + else + { + theTria2 = elem; + // theTria1 must be element with minimum ID + if ( theTria2->GetID() < theTria1->GetID() ) + std::swap( theTria2, theTria1 ); + return true; + } } } - return ( theTria1 && theTria2 ); + return false; } //======================================================================= @@ -927,9 +1061,9 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, // 4 +--+--+ 3 // 8 - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - if(!GetNodesFromTwoTria(tr1,tr2,N1,N2)) + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + 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) @@ -981,82 +1115,49 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) if ( !it || !it->more() ) return false; - switch ( theElem->GetType() ) { + const SMDSAbs_ElementType type = theElem->GetType(); + if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume ) + return false; - 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 ); - } + const SMDSAbs_EntityType geomType = theElem->GetEntityType(); + if ( geomType == SMDSEntity_Polyhedra ) // polyhedron + { + const SMDS_VtkVolume* aPolyedre = + dynamic_cast( theElem ); + if (!aPolyedre) { + MESSAGE("Warning: bad volumic element"); + return false; } - } - case SMDSAbs_Volume: { - if (theElem->IsPoly()) { - // TODO reorient vtk polyhedron - MESSAGE("reorient vtk polyhedron ?"); - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( theElem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - return false; - } - - int nbFaces = aPolyedre->NbFaces(); - vector poly_nodes; - vector quantities (nbFaces); + const 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; + // 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); - } + 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 ); - - } - else { - SMDS_VolumeTool vTool; - if ( !vTool.Set( theElem )) - return false; - vTool.Inverse(); - MESSAGE("ChangeElementNodes reorient: check vTool.Inverse"); - return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() ); } + return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities ); } - default:; + else // other elements + { + vector nodes( theElem->begin_nodes(), theElem->end_nodes() ); + const std::vector& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() ); + if ( interlace.empty() ) + { + std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case + } + else + { + SMDS_MeshCell::applyInterlace( interlace, nodes ); + } + return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() ); } - return false; } @@ -1065,7 +1166,7 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) * \brief Reorient faces. * \param theFaces - the faces to reorient. If empty the whole mesh is meant * \param theDirection - desired direction of normal of \a theFace - * \param theFace - one of \a theFaces that sould be orientated according to + * \param theFace - one of \a theFaces that sould be oriented according to * \a theDirection and whose orientation defines orientation of other faces * \return number of reoriented faces. */ @@ -1087,13 +1188,13 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, // orient theFace according to theDirection gp_XYZ normal; - SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false ); + SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false ); if ( normal * theDirection.XYZ() < 0 ) nbReori += Reorient( theFace ); // Orient other faces - set< const SMDS_MeshElement* > startFaces; + set< const SMDS_MeshElement* > startFaces, visitedFaces; TIDSortedElemSet avoidSet; set< SMESH_TLink > checkedLinks; pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew; @@ -1102,16 +1203,26 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, theFaces.erase( theFace ); startFaces.insert( theFace ); + int nodeInd1, nodeInd2; + const SMDS_MeshElement* otherFace; + vector< const SMDS_MeshElement* > facesNearLink; + vector< std::pair< int, int > > nodeIndsOfFace; + set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin(); - while ( startFace != startFaces.end() ) + while ( !startFaces.empty() ) { + startFace = startFaces.begin(); theFace = *startFace; - const int nbNodes = theFace->NbCornerNodes(); + startFaces.erase( startFace ); + if ( !visitedFaces.insert( theFace ).second ) + continue; avoidSet.clear(); avoidSet.insert(theFace); - NLink link( theFace->GetNode( 0 ), 0 ); + NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 ); + + const int nbNodes = theFace->NbCornerNodes(); for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace { link.second = theFace->GetNode(( i+1 ) % nbNodes ); @@ -1120,37 +1231,152 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, { // link has already been checked and won't be encountered more // if the group (theFaces) is manifold - checkedLinks.erase( linkIt_isNew.first ); + //checkedLinks.erase( linkIt_isNew.first ); } else { - int nodeInd1, nodeInd2; - const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second, - theFaces, avoidSet, - & nodeInd1, & nodeInd2); + facesNearLink.clear(); + nodeIndsOfFace.clear(); + while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second, + theFaces, avoidSet, + &nodeInd1, &nodeInd2 ))) + if ( otherFace != theFace) + { + facesNearLink.push_back( otherFace ); + nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 )); + avoidSet.insert( otherFace ); + } + if ( facesNearLink.size() > 1 ) + { + // NON-MANIFOLD mesh shell ! + // select a face most co-directed with theFace, + // other faces won't be visited this time + gp_XYZ NF, NOF; + SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false ); + double proj, maxProj = -1; + for ( size_t i = 0; i < facesNearLink.size(); ++i ) { + SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false ); + if (( proj = Abs( NF * NOF )) > maxProj ) { + maxProj = proj; + otherFace = facesNearLink[i]; + nodeInd1 = nodeIndsOfFace[i].first; + nodeInd2 = nodeIndsOfFace[i].second; + } + } + // not to visit rejected faces + for ( size_t i = 0; i < facesNearLink.size(); ++i ) + if ( facesNearLink[i] != otherFace && theFaces.size() > 1 ) + visitedFaces.insert( facesNearLink[i] ); + } + else if ( facesNearLink.size() == 1 ) + { + otherFace = facesNearLink[0]; + nodeInd1 = nodeIndsOfFace.back().first; + nodeInd2 = nodeIndsOfFace.back().second; + } if ( otherFace && otherFace != theFace) { - // link must be reversed in otherFace if orientation ot otherFace + // link must be reverse in otherFace if orientation ot otherFace // is same as that of theFace if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 ) { - // cout << "Reorient " << otherFace->GetID() << " near theFace=" <GetID() - // << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl; nbReori += Reorient( otherFace ); } startFaces.insert( otherFace ); - if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces - theFaces.erase( otherFace ); } } - std::swap( link.first, link.second ); + std::swap( link.first, link.second ); // reverse the link } - startFaces.erase( startFace ); - startFace = startFaces.begin(); } return nbReori; } +//================================================================================ +/*! + * \brief Reorient faces basing on orientation of adjacent volumes. + * \param theFaces - faces to reorient. If empty, all mesh faces are treated. + * \param theVolumes - reference volumes. + * \param theOutsideNormal - to orient faces to have their normal + * pointing either \a outside or \a inside the adjacent volumes. + * \return number of reoriented faces. + */ +//================================================================================ + +int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, + TIDSortedElemSet & theVolumes, + const bool theOutsideNormal) +{ + int nbReori = 0; + + SMDS_ElemIteratorPtr faceIt; + if ( theFaces.empty() ) + faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face ); + else + faceIt = elemSetIterator( theFaces ); + + vector< const SMDS_MeshNode* > faceNodes; + TIDSortedElemSet checkedVolumes; + set< const SMDS_MeshNode* > faceNodesSet; + SMDS_VolumeTool volumeTool; + + while ( faceIt->more() ) // loop on given faces + { + const SMDS_MeshElement* face = faceIt->next(); + if ( face->GetType() != SMDSAbs_Face ) + continue; + + const int nbCornersNodes = face->NbCornerNodes(); + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + + checkedVolumes.clear(); + SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* volume = vIt->next(); + + if ( !checkedVolumes.insert( volume ).second ) + continue; + if ( !theVolumes.empty() && !theVolumes.count( volume )) + continue; + + // is volume adjacent? + bool allNodesCommon = true; + for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN ) + allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 ); + if ( !allNodesCommon ) + continue; + + // get nodes of a corresponding volume facet + faceNodesSet.clear(); + faceNodesSet.insert( faceNodes.begin(), faceNodes.end() ); + volumeTool.Set( volume ); + int facetID = volumeTool.GetFaceIndex( faceNodesSet ); + if ( facetID < 0 ) continue; + volumeTool.SetExternalNormal(); + const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID ); + + // compare order of faceNodes and facetNodes + const int iQ = 1 + ( nbCornersNodes < faceNodes.size() ); + int iNN[2]; + for ( int i = 0; i < 2; ++i ) + { + const SMDS_MeshNode* n = facetNodes[ i*iQ ]; + for ( int iN = 0; iN < nbCornersNodes; ++iN ) + if ( faceNodes[ iN ] == n ) + { + iNN[ i ] = iN; + break; + } + } + bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1]; + if ( isOutside != theOutsideNormal ) + nbReori += Reorient( face ); + } + } // loop on given faces + + return nbReori; +} + //======================================================================= //function : getBadRate //purpose : @@ -1178,8 +1404,6 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - MESSAGE( "::QuadToTri()" ); - if ( !theCrit.get() ) return false; @@ -1189,7 +1413,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, SMESH_MesherHelper helper( *GetMesh() ); TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { const SMDS_MeshElement* elem = *itElem; if ( !elem || elem->GetType() != SMDSAbs_Face ) continue; @@ -1209,14 +1434,14 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] ); aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit ); - int aShapeId = FindShape( elem ); + const int aShapeId = FindShape( elem ); const SMDS_MeshElement* newElem1 = 0; const SMDS_MeshElement* newElem2 = 0; - if( !elem->IsQuadratic() ) { - - // split liner quadrangle - + if ( !elem->IsQuadratic() ) // split liner quadrangle + { + // for MaxElementLength2D functor we return minimum diagonal for splitting, + // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) if ( aBadRate1 <= aBadRate2 ) { // tr1 + tr2 is better newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); @@ -1228,70 +1453,28 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] ); } } - else { - - // split quadratic quadrangle + else // split quadratic quadrangle + { + helper.SetIsQuadratic( true ); + helper.SetIsBiQuadratic( aNodes.size() == 9 ); - // 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 ); - } - } - // find middle point for (0,1,2,3) - // and create a node in this point; - const SMDS_MeshNode* newN = 0; + helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); if ( aNodes.size() == 9 ) { - // SMDSEntity_BiQuad_Quadrangle - newN = aNodes.back(); - } - else - { - gp_XYZ p( 0,0,0 ); - if ( surface.IsNull() ) - { - for ( int i = 0; i < 4; i++ ) - p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); - p /= 4; - } + helper.SetIsBiQuadratic( true ); + if ( aBadRate1 <= aBadRate2 ) + helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] ); else - { - const SMDS_MeshNode* inFaceNode = 0; - if ( helper.GetNodeUVneedInFaceNode() ) - for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i ) - if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) - inFaceNode = aNodes[ i ]; - - TopoDS_Face face = TopoDS::Face( helper.GetSubShape() ); - gp_XY uv( 0,0 ); - for ( int i = 0; i < 4; i++ ) - uv += helper.GetNodeUV( face, aNodes[i], inFaceNode ); - uv /= 4.; - p = surface->Value( uv.X(), uv.Y() ).XYZ(); - } - newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); - myLastCreatedNodes.Append(newN); + helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] ); } // create a new element if ( aBadRate1 <= aBadRate2 ) { - newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], - aNodes[6], aNodes[7], newN ); - newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1], - newN, aNodes[4], aNodes[5] ); + newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] ); + newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] ); } else { - newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], - aNodes[7], aNodes[4], newN ); - newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2], - newN, aNodes[5], aNodes[6] ); + newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] ); + newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] ); } } // quadratic case @@ -1304,43 +1487,166 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, // put a new triangle on the same shape if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem1, aShapeId ); - aMesh->SetMeshElementOnShape( newElem2, aShapeId ); - } + aMesh->SetMeshElementOnShape( newElem1, aShapeId ); + aMesh->SetMeshElementOnShape( newElem2, aShapeId ); + aMesh->RemoveElement( elem ); } return true; } //======================================================================= -//function : BestSplit -//purpose : Find better diagonal for cutting. +/*! + * \brief Split each of given quadrangles into 4 triangles. + * \param theElems - The faces to be splitted. If empty all faces are split. + */ //======================================================================= -int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, - SMESH::Controls::NumericalFunctorPtr theCrit) +void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - if (!theCrit.get()) - return -1; + SMESH_MesherHelper helper( *GetMesh() ); + helper.SetElementsOnShape( true ); - if (!theQuad || theQuad->GetType() != SMDSAbs_Face ) - return -1; + SMDS_ElemIteratorPtr faceIt; + if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face); + else faceIt = elemSetIterator( theElems ); - if( theQuad->NbNodes()==4 || - (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) { + bool checkUV; + gp_XY uv [9]; uv[8] = gp_XY(0,0); + gp_XYZ xyz[9]; + vector< const SMDS_MeshNode* > nodes; + SMESHDS_SubMesh* subMeshDS; + TopoDS_Face F; + Handle(Geom_Surface) surface; + TopLoc_Location loc; - // 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() ); - } + while ( faceIt->more() ) + { + const SMDS_MeshElement* quad = faceIt->next(); + if ( !quad || quad->NbCornerNodes() != 4 ) + continue; + + // get a surface the quad is on + + if ( quad->getshapeId() < 1 ) + { + F.Nullify(); + helper.SetSubShape( 0 ); + subMeshDS = 0; + } + else if ( quad->getshapeId() != helper.GetSubShapeID() ) + { + helper.SetSubShape( quad->getshapeId() ); + if ( !helper.GetSubShape().IsNull() && + helper.GetSubShape().ShapeType() == TopAbs_FACE ) + { + F = TopoDS::Face( helper.GetSubShape() ); + surface = BRep_Tool::Surface( F, loc ); + subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() ); + } + else + { + helper.SetSubShape( 0 ); + subMeshDS = 0; + } + } + + // create a central node + + const SMDS_MeshNode* nCentral; + nodes.assign( quad->begin_nodes(), quad->end_nodes() ); + + if ( nodes.size() == 9 ) + { + nCentral = nodes.back(); + } + else + { + size_t iN = 0; + if ( F.IsNull() ) + { + for ( ; iN < nodes.size(); ++iN ) + xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] ); + + for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle + xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] ); + + xyz[ 8 ] = helper.calcTFI( 0.5, 0.5, + xyz[0], xyz[1], xyz[2], xyz[3], + xyz[4], xyz[5], xyz[6], xyz[7] ); + } + else + { + for ( ; iN < nodes.size(); ++iN ) + uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV ); + + for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle + uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] ); + + uv[ 8 ] = helper.calcTFI( 0.5, 0.5, + uv[0], uv[1], uv[2], uv[3], + uv[4], uv[5], uv[6], uv[7] ); + + gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc ); + xyz[ 8 ] = p.XYZ(); + } + + nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0, + uv[8].X(), uv[8].Y() ); + myLastCreatedNodes.Append( nCentral ); + } + + // create 4 triangles + + GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false ); + + helper.SetIsQuadratic ( nodes.size() > 4 ); + helper.SetIsBiQuadratic( nodes.size() == 9 ); + if ( helper.GetIsQuadratic() ) + helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad )); + + for ( int i = 0; i < 4; ++i ) + { + SMDS_MeshElement* tria = helper.AddFace( nodes[ i ], + nodes[(i+1)%4], + nCentral ); + ReplaceElemInGroups( tria, quad, GetMeshDS() ); + myLastCreatedElems.Append( tria ); + } + } +} + +//======================================================================= +//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] ); @@ -1350,7 +1656,8 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] ); SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] ); aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit ); - + // for MaxElementLength2D functor we return minimum diagonal for splitting, + // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better return 1; // diagonal 1-3 @@ -1428,44 +1735,110 @@ namespace const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3, thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 }; + // Methods of splitting hexahedron into prisms + + const int theHexTo4Prisms_BT[6*4+1] = // bottom-top + { + 0, 1, 8, 4, 5, 9, 1, 2, 8, 5, 6, 9, 2, 3, 8, 6, 7, 9, 3, 0, 8, 7, 4, 9, -1 + }; + const int theHexTo4Prisms_LR[6*4+1] = // left-right + { + 1, 0, 8, 2, 3, 9, 0, 4, 8, 3, 7, 9, 4, 5, 8, 7, 6, 9, 5, 1, 8, 6, 2, 9, -1 + }; + const int theHexTo4Prisms_FB[6*4+1] = // front-back + { + 0, 3, 9, 1, 2, 8, 3, 7, 9, 2, 6, 8, 7, 4, 9, 6, 5, 8, 4, 0, 9, 5, 1, 8, -1 + }; + + const int theHexTo2Prisms_BT_1[6*2+1] = + { + 0, 1, 3, 4, 5, 7, 1, 2, 3, 5, 6, 7, -1 + }; + const int theHexTo2Prisms_BT_2[6*2+1] = + { + 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7, -1 + }; + const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 }; + + const int theHexTo2Prisms_LR_1[6*2+1] = + { + 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1 + }; + const int theHexTo2Prisms_LR_2[6*2+1] = + { + 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1 + }; + const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 }; + + const int theHexTo2Prisms_FB_1[6*2+1] = + { + 0, 3, 4, 1, 2, 5, 3, 7, 4, 2, 6, 5, -1 + }; + const int theHexTo2Prisms_FB_2[6*2+1] = + { + 0, 3, 7, 1, 2, 7, 0, 7, 4, 1, 6, 5, -1 + }; + const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 }; + + struct TTriangleFacet //!< stores indices of three nodes of tetra facet { int _n1, _n2, _n3; TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {} bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); } - bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const; + bool hasAdjacentVol( const SMDS_MeshElement* elem, + const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const; }; struct TSplitMethod { - int _nbTetra; + int _nbSplits; + int _nbCorners; const int* _connectivity; //!< foursomes of tetra connectivy finished by -1 bool _baryNode; //!< additional node is to be created at cell barycenter bool _ownConn; //!< to delete _connectivity in destructor map _faceBaryNode; //!< map face index to node at BC of face TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false) - : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} + : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; } bool hasFacet( const TTriangleFacet& facet ) const { - const int* tetConn = _connectivity; - for ( ; tetConn[0] >= 0; tetConn += 4 ) - if (( facet.contains( tetConn[0] ) + - facet.contains( tetConn[1] ) + - facet.contains( tetConn[2] ) + - facet.contains( tetConn[3] )) == 3 ) - return true; + if ( _nbCorners == 4 ) + { + const int* tetConn = _connectivity; + for ( ; tetConn[0] >= 0; tetConn += 4 ) + if (( facet.contains( tetConn[0] ) + + facet.contains( tetConn[1] ) + + facet.contains( tetConn[2] ) + + facet.contains( tetConn[3] )) == 3 ) + return true; + } + else // prism, _nbCorners == 6 + { + const int* prismConn = _connectivity; + for ( ; prismConn[0] >= 0; prismConn += 6 ) + { + if (( facet.contains( prismConn[0] ) && + facet.contains( prismConn[1] ) && + facet.contains( prismConn[2] )) + || + ( facet.contains( prismConn[3] ) && + facet.contains( prismConn[4] ) && + facet.contains( prismConn[5] ))) + return true; + } + } return false; } }; //======================================================================= /*! - * \brief return TSplitMethod for the given element + * \brief return TSplitMethod for the given element to split into tetrahedra */ //======================================================================= - TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) + TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) { const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; @@ -1490,8 +1863,8 @@ namespace { TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); - if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 ); - else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 ); + if ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 ); + else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 ); } else { @@ -1504,7 +1877,7 @@ namespace TTriangleFacet t023( nInd[ iQ * ( iCom )], nInd[ iQ * ( (iCom+2)%nbNodes )], nInd[ iQ * ( (iCom+3)%nbNodes )]); - if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() )) + if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() )) { triaSplits.push_back( t012 ); triaSplits.push_back( t023 ); @@ -1544,12 +1917,12 @@ namespace default: nbVariants = 0; } - for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant ) + for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant ) { // check method compliancy with adjacent tetras, // all found splits must be among facets of tetras described by this method method = TSplitMethod( nbTet, connVariants[variant] ); - if ( hasAdjacentSplits && method._nbTetra > 0 ) + if ( hasAdjacentSplits && method._nbSplits > 0 ) { bool facetCreated = true; for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) @@ -1563,7 +1936,7 @@ namespace } } } - if ( method._nbTetra < 1 ) + if ( method._nbSplits < 1 ) { // No standard method is applicable, use a generic solution: // each facet of a volume is split into triangles and @@ -1657,7 +2030,7 @@ namespace connectivity[ connSize++ ] = baryCenInd; } } - method._nbTetra += nbTet; + method._nbSplits += nbTet; } // loop on volume faces @@ -1667,13 +2040,132 @@ namespace return method; } + //======================================================================= + /*! + * \brief return TSplitMethod to split haxhedron into prisms + */ + //======================================================================= + + TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol, + const int methodFlags, + const int facetToSplit) + { + // order of facets in HEX according to SMDS_VolumeTool::Hexa_F : + // B, T, L, B, R, F + const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2] + + if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS ) + { + static TSplitMethod to4methods[4]; // order BT, LR, FB + if ( to4methods[iF]._nbSplits == 0 ) + { + switch ( iF ) { + case 0: + to4methods[iF]._connectivity = theHexTo4Prisms_BT; + to4methods[iF]._faceBaryNode[ 0 ] = 0; + to4methods[iF]._faceBaryNode[ 1 ] = 0; + break; + case 1: + to4methods[iF]._connectivity = theHexTo4Prisms_LR; + to4methods[iF]._faceBaryNode[ 2 ] = 0; + to4methods[iF]._faceBaryNode[ 4 ] = 0; + break; + case 2: + to4methods[iF]._connectivity = theHexTo4Prisms_FB; + to4methods[iF]._faceBaryNode[ 3 ] = 0; + to4methods[iF]._faceBaryNode[ 5 ] = 0; + break; + default: return to4methods[3]; + } + to4methods[iF]._nbSplits = 4; + to4methods[iF]._nbCorners = 6; + } + return to4methods[iF]; + } + // else if ( methodFlags == HEXA_TO_2_PRISMS ) + + TSplitMethod method; + + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + + const int nbVariants = 2, nbSplits = 2; + const int** connVariants = 0; + switch ( iF ) { + case 0: connVariants = theHexTo2Prisms_BT; break; + case 1: connVariants = theHexTo2Prisms_LR; break; + case 2: connVariants = theHexTo2Prisms_FB; break; + default: return method; + } + + // look for prisms adjacent via facetToSplit and an opposite one + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit; + int nbNodes = vol.NbFaceNodes( iFacet ) / iQ; + if ( nbNodes != 4 ) return method; + + const int* nInd = vol.GetFaceNodesIndices( iFacet ); + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + TTriangleFacet* t; + if ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA )) + t = &t012; + else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA )) + t = &t123; + else + continue; + + // there are adjacent prism + for ( int variant = 0; variant < nbVariants; ++variant ) + { + // check method compliancy with adjacent prisms, + // the found prism facets must be among facets of prisms described by current method + method._nbSplits = nbSplits; + method._nbCorners = 6; + method._connectivity = connVariants[ variant ]; + if ( method.hasFacet( *t )) + return method; + } + } + + // No adjacent prisms. Select a variant with a best aspect ratio. + + double badness[2] = { 0, 0 }; + static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio); + const SMDS_MeshNode** nodes = vol.GetNodes(); + for ( int variant = 0; variant < nbVariants; ++variant ) + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit; + const int* nInd = vol.GetFaceNodesIndices( iFacet ); + + method._connectivity = connVariants[ variant ]; + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123; + + SMDS_FaceOfNodes tria ( nodes[ t->_n1 ], + nodes[ t->_n2 ], + nodes[ t->_n3 ] ); + badness[ variant ] += getBadRate( &tria, aspectRatio ); + } + const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] ); + + method._nbSplits = nbSplits; + method._nbCorners = 6; + method._connectivity = connVariants[ iBetter ]; + + return method; + } + //================================================================================ /*! * \brief Check if there is a tetraherdon adjacent to the given element via this facet */ //================================================================================ - bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const + bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement* elem, + const SMDSAbs_GeometryType geom ) const { // find the tetrahedron including the three nodes of facet const SMDS_MeshNode* n1 = elem->GetNode(_n1); @@ -1683,16 +2175,16 @@ namespace while ( volIt1->more() ) { const SMDS_MeshElement* v = volIt1->next(); - SMDSAbs_EntityType type = v->GetEntityType(); - if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra ) + if ( v->GetGeomType() != geom ) continue; - if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 ) + const int lastCornerInd = v->NbCornerNodes() - 1; + if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd ) continue; // medium node not allowed const int ind2 = v->GetNodeIndex( n2 ); - if ( ind2 < 0 || 3 < ind2 ) + if ( ind2 < 0 || lastCornerInd < ind2 ) continue; const int ind3 = v->GetNodeIndex( n3 ); - if ( ind3 < 0 || 3 < ind3 ) + if ( ind3 < 0 || lastCornerInd < ind3 ) continue; return true; } @@ -1725,52 +2217,57 @@ namespace } // namespace //======================================================================= -//function : SplitVolumesIntoTetra -//purpose : Split volume elements into tetrahedra. +//function : SplitVolumes +//purpose : Split volume elements into tetrahedra or prisms. +// If facet ID < 0, element is split into tetrahedra, +// else a hexahedron is split into prisms so that the given facet is +// split into triangles //======================================================================= -void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, - const int theMethodFlags) +void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, + const int theMethodFlags) { - // std-like iterator on coordinates of nodes of mesh element - typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator; - NXyzIterator xyzEnd; - SMDS_VolumeTool volTool; - SMESH_MesherHelper helper( *GetMesh()); + SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh()); + fHelper.ToFixNodeParameters( true ); SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1); SMESHDS_SubMesh* fSubMesh = 0;//subMesh; - + SMESH_SequenceOfElemPtr newNodes, newElems; // map face of volume to it's baricenrtic node map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; double bc[3]; + vector splitVols; - TIDSortedElemSet::const_iterator elem = theElems.begin(); - for ( ; elem != theElems.end(); ++elem ) + TFacetOfElem::const_iterator elem2facet = theElems.begin(); + for ( ; elem2facet != theElems.end(); ++elem2facet ) { - if ( (*elem)->GetType() != SMDSAbs_Volume ) + const SMDS_MeshElement* elem = elem2facet->first; + const int facetToSplit = elem2facet->second; + if ( elem->GetType() != SMDSAbs_Volume ) continue; - SMDSAbs_EntityType geomType = (*elem)->GetEntityType(); + const SMDSAbs_EntityType geomType = elem->GetEntityType(); if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra ) continue; - if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange... + if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange... - TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags ); - if ( splitMethod._nbTetra < 1 ) continue; + TSplitMethod splitMethod = ( facetToSplit < 0 ? + getTetraSplitMethod( volTool, theMethodFlags ) : + getPrismSplitMethod( volTool, theMethodFlags, facetToSplit )); + if ( splitMethod._nbSplits < 1 ) continue; // find submesh to add new tetras to - if ( !subMesh || !subMesh->Contains( *elem )) + if ( !subMesh || !subMesh->Contains( elem )) { - int shapeID = FindShape( *elem ); + int shapeID = FindShape( elem ); helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh subMesh = GetMeshDS()->MeshElements( shapeID ); } int iQ; - if ( (*elem)->IsQuadratic() ) + if ( elem->IsQuadratic() ) { iQ = 2; // add quadratic links to the helper @@ -1788,7 +2285,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, iQ = 1; helper.SetIsQuadratic( false ); } - vector nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() ); + vector nodes( volTool.GetNodes(), + volTool.GetNodes() + elem->NbNodes() ); helper.SetElementsOnShape( true ); if ( splitMethod._baryNode ) { @@ -1816,16 +2314,25 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, } } - // make tetras - vector tetras( splitMethod._nbTetra ); // splits of a volume - const int* tetConn = splitMethod._connectivity; - for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 ) - newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ], - nodes[ tetConn[1] ], - nodes[ tetConn[2] ], - nodes[ tetConn[3] ])); + // make new volumes + splitVols.resize( splitMethod._nbSplits ); // splits of a volume + const int* volConn = splitMethod._connectivity; + if ( splitMethod._nbCorners == 4 ) // tetra + for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners ) + newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ], + nodes[ volConn[1] ], + nodes[ volConn[2] ], + nodes[ volConn[3] ])); + else // prisms + for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners ) + newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ], + nodes[ volConn[1] ], + nodes[ volConn[2] ], + nodes[ volConn[3] ], + nodes[ volConn[4] ], + nodes[ volConn[5] ])); - ReplaceElemInGroups( *elem, tetras, GetMeshDS() ); + ReplaceElemInGroups( elem, splitVols, GetMeshDS() ); // Split faces on sides of the split volume @@ -1854,17 +2361,37 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, map::iterator iF_n = splitMethod._faceBaryNode.find(iF); if ( iF_n != splitMethod._faceBaryNode.end() ) { + const SMDS_MeshNode *baryNode = iF_n->second; for ( int iN = 0; iN < nbNodes*iQ; iN += iQ ) { const SMDS_MeshNode* n1 = fNodes[iN]; const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)]; - const SMDS_MeshNode *n3 = iF_n->second; + const SMDS_MeshNode *n3 = baryNode; if ( !volTool.IsFaceExternal( iF )) swap( n2, n3 ); triangles.push_back( helper.AddFace( n1,n2,n3 )); - - if ( fSubMesh && n3->getshapeId() < 1 ) - fSubMesh->AddNode( n3 ); + } + if ( fSubMesh ) // update position of the bary node on geometry + { + if ( subMesh ) + subMesh->RemoveNode( baryNode, false ); + GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() ); + const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() ); + if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE ) + { + fHelper.SetSubShape( s ); + gp_XY uv( 1e100, 1e100 ); + double distXYZ[4]; + if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode, + uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) && + uv.X() < 1e100 ) + { + // node is too far from the surface + GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] ); + const_cast( baryNode )->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() ))); + } + } } } else @@ -1894,6 +2421,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, } } list< TTriangleFacet >::iterator facet = facets.begin(); + if ( facet == facets.end() ) + break; for ( ; facet != facets.end(); ++facet ) { if ( !volTool.IsFaceExternal( iF )) @@ -1912,11 +2441,11 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, } ReplaceElemInGroups( face, triangles, GetMeshDS() ); GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false ); - } + } // while a face based on facet nodes exists } // loop on volume faces to split them into triangles - GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false ); + GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); if ( geomType == SMDSEntity_TriQuad_Hexa ) { @@ -1926,124 +2455,498 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, GetMeshDS()->RemoveNode( volNodes[i] ); } } // loop on volumes to split - + myLastCreatedNodes = newNodes; myLastCreatedElems = newElems; } //======================================================================= -//function : AddToSameGroups -//purpose : add elemToAdd to the groups the elemInGroups belongs to +//function : GetHexaFacetsToSplit +//purpose : For hexahedra that will be split into prisms, finds facets to +// split into triangles. Only hexahedra adjacent to the one closest +// to theFacetNormal.Location() are returned. +//param [in,out] theHexas - the hexahedra +//param [in] theFacetNormal - facet normal +//param [out] theFacets - the hexahedra and found facet IDs //======================================================================= -void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, - const SMDS_MeshElement* elemInGroups, - SMESHDS_Mesh * aMesh) +void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, + const gp_Ax1& theFacetNormal, + TFacetOfElem & theFacets) { - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) { - set::const_iterator grIt = groups.begin(); - for ( ; grIt != groups.end(); grIt++ ) { - SMESHDS_Group* group = dynamic_cast( *grIt ); - if ( group && group->Contains( elemInGroups )) - group->SMDSGroup().Add( elemToAdd ); - } - } -} + #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): " + // Find a hexa closest to the location of theFacetNormal -//======================================================================= -//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()) + const SMDS_MeshElement* startHex; { - 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); - } - } -} + // get SMDS_ElemIteratorPtr on theHexas + typedef const SMDS_MeshElement* TValue; + typedef TIDSortedElemSet::iterator TSetIterator; + typedef SMDS::SimpleAccessor TAccesor; + typedef SMDS_MeshElement::GeomFilter TFilter; + typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter; + SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr + ( new TElemSetIter( theHexas.begin(), + theHexas.end(), + SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA ))); -//================================================================================ -/*! - * \brief Replace elemToRm by elemToAdd in the all groups - */ -//================================================================================ + SMESH_ElementSearcher* searcher = + SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt ); -void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, - const SMDS_MeshElement* elemToAdd, - SMESHDS_Mesh * aMesh) -{ - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) { - set::const_iterator grIt = groups.begin(); - for ( ; grIt != groups.end(); grIt++ ) { - SMESHDS_Group* group = dynamic_cast( *grIt ); - if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd ) - group->SMDSGroup().Add( elemToAdd ); - } - } -} + startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume ); -//================================================================================ -/*! - * \brief Replace elemToRm by elemToAdd in the all groups - */ -//================================================================================ + delete searcher; -void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, - const vector& elemToAdd, - SMESHDS_Mesh * aMesh) -{ - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) - { - set::const_iterator grIt = groups.begin(); - for ( ; grIt != groups.end(); grIt++ ) { - SMESHDS_Group* group = dynamic_cast( *grIt ); - if ( group && group->SMDSGroup().Remove( elemToRm ) ) - for ( int i = 0; i < elemToAdd.size(); ++i ) - group->SMDSGroup().Add( elemToAdd[ i ] ); - } + if ( !startHex ) + throw SALOME_Exception( THIS_METHOD "startHex not found"); } -} -//======================================================================= -//function : QuadToTri -//purpose : Cut quadrangles into triangles. -// theCrit is used to select a diagonal to cut -//======================================================================= + // Select a facet of startHex by theFacetNormal -bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, - const bool the13Diag) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + SMDS_VolumeTool vTool( startHex ); + double norm[3], dot, maxDot = 0; + int facetID = -1; + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] )) + { + dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] ))); + if ( dot > maxDot ) + { + facetID = iF; + maxDot = dot; + } + } + if ( facetID < 0 ) + throw SALOME_Exception( THIS_METHOD "facet of startHex not found"); - MESSAGE( "::QuadToTri()" ); + // Fill theFacets starting from facetID of startHex - SMESHDS_Mesh * aMesh = GetMeshDS(); + // facets used for seach of volumes adjacent to already treated ones + typedef pair< TFacetOfElem::iterator, int > TElemFacets; + typedef map< TVolumeFaceKey, TElemFacets > TFacetMap; + TFacetMap facetsToCheck; - Handle(Geom_Surface) surface; - SMESH_MesherHelper helper( *GetMesh() ); + set facetNodes; + const SMDS_MeshElement* curHex; - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() != SMDSAbs_Face ) - continue; - bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8; - if(!isquad) continue; + const bool allHex = ( theHexas.size() == myMesh->NbHexas() ); - if(elem->NbNodes()==4) { + while ( startHex ) + { + // move in two directions from startHex via facetID + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + curHex = startHex; + int curFacet = facetID; + if ( is2nd ) // do not treat startHex twice + { + vTool.Set( curHex ); + if ( vTool.IsFreeFace( curFacet, &curHex )) + { + curHex = 0; + } + else + { + vTool.GetFaceNodes( curFacet, facetNodes ); + vTool.Set( curHex ); + curFacet = vTool.GetFaceIndex( facetNodes ); + } + } + while ( curHex ) + { + // store a facet to split + if ( curHex->GetGeomType() != SMDSGeom_HEXA ) + { + theFacets.insert( make_pair( curHex, -1 )); + break; + } + if ( !allHex && !theHexas.count( curHex )) + break; + + pair< TFacetOfElem::iterator, bool > facetIt2isNew = + theFacets.insert( make_pair( curHex, curFacet )); + if ( !facetIt2isNew.second ) + break; + + // remember not-to-split facets in facetsToCheck + int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet ); + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + if ( iF == curFacet && iF == oppFacet ) + continue; + TVolumeFaceKey facetKey ( vTool, iF ); + TElemFacets elemFacet( facetIt2isNew.first, iF ); + pair< TFacetMap::iterator, bool > it2isnew = + facetsToCheck.insert( make_pair( facetKey, elemFacet )); + if ( !it2isnew.second ) + facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked + } + // pass to a volume adjacent via oppFacet + if ( vTool.IsFreeFace( oppFacet, &curHex )) + { + curHex = 0; + } + else + { + // get a new curFacet + vTool.GetFaceNodes( oppFacet, facetNodes ); + vTool.Set( curHex ); + curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet ); + } + } + } // move in two directions from startHex via facetID + + // Find a new startHex by facetsToCheck + + startHex = 0; + facetID = -1; + TFacetMap::iterator fIt = facetsToCheck.begin(); + while ( !startHex && fIt != facetsToCheck.end() ) + { + const TElemFacets& elemFacets = fIt->second; + const SMDS_MeshElement* hex = elemFacets.first->first; + int splitFacet = elemFacets.first->second; + int lateralFacet = elemFacets.second; + facetsToCheck.erase( fIt ); + fIt = facetsToCheck.begin(); + + vTool.Set( hex ); + if ( vTool.IsFreeFace( lateralFacet, &curHex ) || + curHex->GetGeomType() != SMDSGeom_HEXA ) + continue; + if ( !allHex && !theHexas.count( curHex )) + continue; + + startHex = curHex; + + // find a facet of startHex to split + + set lateralNodes; + vTool.GetFaceNodes( lateralFacet, lateralNodes ); + vTool.GetFaceNodes( splitFacet, facetNodes ); + int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet ); + vTool.Set( startHex ); + lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet ); + + // look for a facet of startHex having common nodes with facetNodes + // but not lateralFacet + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + if ( iF == lateralFacet ) + continue; + int nbCommonNodes = 0; + const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF ); + for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN ) + nbCommonNodes += facetNodes.count( nn[ iN ]); + + if ( nbCommonNodes >= 2 ) + { + facetID = iF; + break; + } + } + if ( facetID < 0 ) + throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found"); + } + } // while ( startHex ) + + return; +} + +namespace +{ + //================================================================================ + /*! + * \brief Selects nodes of several elements according to a given interlace + * \param [in] srcNodes - nodes to select from + * \param [out] tgtNodesVec - array of nodes of several elements to fill in + * \param [in] interlace - indices of nodes for all elements + * \param [in] nbElems - nb of elements + * \param [in] nbNodes - nb of nodes in each element + * \param [in] mesh - the mesh + * \param [out] elemQueue - a list to push elements found by the selected nodes + * \param [in] type - type of elements to look for + */ + //================================================================================ + + void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes, + vector< const SMDS_MeshNode* >* tgtNodesVec, + const int* interlace, + const int nbElems, + const int nbNodes, + SMESHDS_Mesh* mesh = 0, + list< const SMDS_MeshElement* >* elemQueue=0, + SMDSAbs_ElementType type=SMDSAbs_All) + { + for ( int iE = 0; iE < nbElems; ++iE ) + { + vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE]; + const int* select = & interlace[iE*nbNodes]; + elemNodes.resize( nbNodes ); + for ( int iN = 0; iN < nbNodes; ++iN ) + elemNodes[iN] = srcNodes[ select[ iN ]]; + } + const SMDS_MeshElement* e; + if ( elemQueue ) + for ( int iE = 0; iE < nbElems; ++iE ) + if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false))) + elemQueue->push_back( e ); + } +} + +//======================================================================= +/* + * Split bi-quadratic elements into linear ones without creation of additional nodes + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ +//======================================================================= + +void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems) +{ + vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8]; + vector splitElems; + list< const SMDS_MeshElement* > elemQueue; + list< const SMDS_MeshElement* >::iterator elemIt; + + SMESHDS_Mesh * mesh = GetMeshDS(); + ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge); + int nbElems, nbNodes; + + TIDSortedElemSet::iterator elemSetIt = theElems.begin(); + for ( ; elemSetIt != theElems.end(); ++elemSetIt ) + { + elemQueue.clear(); + elemQueue.push_back( *elemSetIt ); + for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt ) + { + const SMDS_MeshElement* elem = *elemIt; + switch( elem->GetEntityType() ) + { + case SMDSEntity_TriQuad_Hexa: // HEX27 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = nbNodes = 8; + elemType = & hexaType; + + // get nodes for new elements + static int vInd[8][8] = {{ 0,8,20,11, 16,21,26,24 }, + { 1,9,20,8, 17,22,26,21 }, + { 2,10,20,9, 18,23,26,22 }, + { 3,11,20,10, 19,24,26,23 }, + { 16,21,26,24, 4,12,25,15 }, + { 17,22,26,21, 5,13,25,12 }, + { 18,23,26,22, 6,14,25,13 }, + { 19,24,26,23, 7,15,25,14 }}; + selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes ); + + // add boundary faces to elemQueue + static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11, 20 }, + { 4,5,6,7, 12,13,14,15, 25 }, + { 0,1,5,4, 8,17,12,16, 21 }, + { 1,2,6,5, 9,18,13,17, 22 }, + { 2,3,7,6, 10,19,14,18, 23 }, + { 3,0,4,7, 11,16,15,19, 24 }}; + selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face ); + + // add boundary segments to elemQueue + static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 }, + { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 }, + { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Triangle: // TRIA7 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 3; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Quadrangle: // QUAD9 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 4; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_Quad_Edge: + { + if ( elemIt == elemQueue.begin() ) + continue; // an elem is in theElems + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 2; + nbNodes = 2; + elemType = & segType; + + // get nodes for new elements + static int eInd[2][2] = {{ 0,2 }, { 2,1 }}; + selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes ); + break; + } + default: continue; + } // switch( elem->GetEntityType() ) + + // Create new elements + + SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() ); + + splitElems.clear(); + + //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one + mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); + //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType )); + //elemType->SetID( -1 ); + + for ( int iE = 0; iE < nbElems; ++iE ) + splitElems.push_back( AddElement( splitNodes[ iE ], *elemType )); + + + ReplaceElemInGroups( elem, splitElems, mesh ); + + if ( subMesh ) + for ( size_t i = 0; i < splitElems.size(); ++i ) + subMesh->AddElement( splitElems[i] ); + } + } +} + +//======================================================================= +//function : AddToSameGroups +//purpose : add elemToAdd to the groups the elemInGroups belongs to +//======================================================================= + +void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, + const SMDS_MeshElement* elemInGroups, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->Contains( elemInGroups )) + group->SMDSGroup().Add( 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); + } + } +} + +//================================================================================ +/*! + * \brief Replace elemToRm by elemToAdd in the all groups + */ +//================================================================================ + +void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + const SMDS_MeshElement* elemToAdd, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd ) + group->SMDSGroup().Add( elemToAdd ); + } + } +} + +//================================================================================ +/*! + * \brief Replace elemToRm by elemToAdd in the all groups + */ +//================================================================================ + +void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + const vector& elemToAdd, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) + { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->SMDSGroup().Remove( elemToRm ) ) + for ( int i = 0; i < elemToAdd.size(); ++i ) + group->SMDSGroup().Add( elemToAdd[ i ] ); + } + } +} + +//======================================================================= +//function : QuadToTri +//purpose : Cut quadrangles into triangles. +// theCrit is used to select a diagonal to cut +//======================================================================= + +bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, + const bool the13Diag) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + MESSAGE( "::QuadToTri()" ); + + SMESHDS_Mesh * aMesh = GetMeshDS(); + + Handle(Geom_Surface) surface; + SMESH_MesherHelper helper( *GetMesh() ); + + TIDSortedElemSet::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8; + if(!isquad) continue; + + if(elem->NbNodes()==4) { // retrieve element nodes const SMDS_MeshNode* aNodes [4]; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); @@ -2287,18 +3190,19 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL; TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { const SMDS_MeshElement* elem = *itElem; if(!elem || elem->GetType() != SMDSAbs_Face ) continue; - bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic()); - if(!IsTria) continue; + bool IsTria = ( elem->NbCornerNodes()==3 ); + if (!IsTria) continue; // retrieve element nodes const SMDS_MeshNode* aNodes [4]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + SMDS_NodeIteratorPtr itN = elem->nodeIterator(); int i = 0; - while ( i<3 ) - aNodes[ i++ ] = cast2Node( itN->next() ); + while ( i < 3 ) + aNodes[ i++ ] = itN->next(); aNodes[ 3 ] = aNodes[ 0 ]; // fill maps @@ -2443,31 +3347,31 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, } // Make quadrangles - // and remove fused elems and removed links from the maps + // and remove fused elems and remove links from the maps mapEl_setLi.erase( tr1 ); - if ( Ok12 ) { + if ( Ok12 ) + { mapEl_setLi.erase( tr2 ); mapLi_listEl.erase( *link12 ); - if(tr1->NbNodes()==3) { + if ( tr1->NbNodes() == 3 ) + { const SMDS_MeshElement* newElem = 0; newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] ); myLastCreatedElems.Append(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } + aMesh->SetMeshElementOnShape( newElem, aShapeId ); aMesh->RemoveElement( tr1 ); aMesh->RemoveElement( tr2 ); } 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) + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + getNodesFromTwoTria(tr1,tr2,N1,N2); + // now we receive following N1 and N2 (using numeration as in image in InverseDiag()) // 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 + // i.e. first nodes from both arrays form a new diagonal const SMDS_MeshNode* aNodes[8]; aNodes[0] = N1[0]; aNodes[1] = N1[1]; @@ -2478,44 +3382,50 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, aNodes[6] = N2[3]; aNodes[7] = N1[5]; const SMDS_MeshElement* newElem = 0; - newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], - aNodes[4], aNodes[5], aNodes[6], aNodes[7]); + if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]); + else + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7]); myLastCreatedElems.Append(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } + aMesh->SetMeshElementOnShape( newElem, aShapeId ); aMesh->RemoveElement( tr1 ); aMesh->RemoveElement( tr2 ); // remove middle node (9) - GetMeshDS()->RemoveNode( N1[4] ); + if ( N1[4]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[4] ); + if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[6] ); + if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N2[6] ); } } - else if ( Ok13 ) { + else if ( Ok13 ) + { mapEl_setLi.erase( tr3 ); mapLi_listEl.erase( *link13 ); - if(tr1->NbNodes()==3) { + if ( tr1->NbNodes() == 3 ) { const SMDS_MeshElement* newElem = 0; newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] ); myLastCreatedElems.Append(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } + aMesh->SetMeshElementOnShape( newElem, aShapeId ); aMesh->RemoveElement( tr1 ); aMesh->RemoveElement( tr3 ); } else { - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - GetNodesFromTwoTria(tr1,tr3,N1,N2); + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + 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 + // i.e. first nodes from both arrays form a new diagonal const SMDS_MeshNode* aNodes[8]; aNodes[0] = N1[0]; aNodes[1] = N1[1]; @@ -2526,19 +3436,26 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, aNodes[6] = N2[3]; aNodes[7] = N1[5]; const SMDS_MeshElement* newElem = 0; - newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], - aNodes[4], aNodes[5], aNodes[6], aNodes[7]); + if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]); + else + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7]); myLastCreatedElems.Append(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } + aMesh->SetMeshElementOnShape( newElem, aShapeId ); aMesh->RemoveElement( tr1 ); aMesh->RemoveElement( tr3 ); // remove middle node (9) - GetMeshDS()->RemoveNode( N1[4] ); + if ( N1[4]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[4] ); + if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[6] ); + if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N2[6] ); } } @@ -2854,7 +3771,7 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode, const SMDS_MeshElement* elem = elemIt->next(); if(elem->GetType() == SMDSAbs_0DElement) continue; - + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); if ( elem->GetType() == SMDSAbs_Volume ) { @@ -3011,13 +3928,8 @@ static bool getClosestUV (Extrema_GenExtPS& projector, if ( projector.IsDone() ) { double u, v, minVal = DBL_MAX; for ( int i = projector.NbExt(); i > 0; i-- ) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 if ( projector.SquareDistance( i ) < minVal ) { minVal = projector.SquareDistance( i ); -#else - if ( projector.Value( i ) < minVal ) { - minVal = projector.Value( i ); -#endif projector.Point( i ).Parameter( u, v ); } result.SetCoord( u, v ); @@ -3062,7 +3974,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, SMDS_FaceIteratorPtr fIt = aMesh->facesIterator(); while ( fIt->more() ) { const SMDS_MeshElement* face = fIt->next(); - theElems.insert( face ); + theElems.insert( theElems.end(), face ); } } // get all face ids theElems are on @@ -3086,8 +3998,11 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // 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 ) { + SMESH_MesherHelper helper( *GetMesh() ); + + set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end + for ( ; fId != faceIdSet.rend(); ++fId ) + { // get face surface and submesh Handle(Geom_Surface) surface; SMESHDS_SubMesh* faceSubMesh = 0; @@ -3095,7 +4010,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, double fToler2 = 0, f,l; double u1 = 0, u2 = 0, v1 = 0, v2 = 0; bool isUPeriodic = false, isVPeriodic = false; - if ( *fId ) { + if ( *fId ) + { face = TopoDS::Face( aMesh->IndexToShape( *fId )); surface = BRep_Tool::Surface( face ); faceSubMesh = aMesh->MeshElements( *fId ); @@ -3108,6 +4024,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, if ( isVPeriodic ) surface->VPeriod(); surface->Bounds( u1, u2, v1, v2 ); + helper.SetSubShape( face ); } // --------------------------------------------------------- // for elements on a face, find movable and fixed nodes and @@ -3129,7 +4046,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, int nbElemOnFace = 0; itElem = theElems.begin(); // loop on not yet smoothed elements: look for elems on a face - while ( itElem != theElems.end() ) { + while ( itElem != theElems.end() ) + { if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() ) break; // all elements found @@ -3185,12 +4103,15 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // get nodes to check UV list< const SMDS_MeshNode* > uvCheckNodes; + const SMDS_MeshNode* nodeInFace = 0; itN = elem->nodesIterator(); nn = 0; nbn = elem->NbNodes(); if(elem->IsQuadratic()) nbn = nbn/2; while ( nn++ < nbn ) { node = static_cast( itN->next() ); + if ( node->GetPosition()->GetDim() == 2 ) + nodeInFace = node; if ( uvMap.find( node ) == uvMap.end() ) uvCheckNodes.push_back( node ); // add nodes of elems sharing node @@ -3216,41 +4137,21 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, const SMDS_PositionPtr& pos = node->GetPosition(); posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; // get existing UV - switch ( posType ) { - case SMDS_TOP_FACE: { - SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos; - uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() ); - break; - } - case SMDS_TOP_EDGE: { - TopoDS_Shape S = aMesh->IndexToShape( node->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 )->GetUParameter(); - uv = pcurve->Value( u ).XY(); - } - break; - } - case SMDS_TOP_VERTEX: { - TopoDS_Shape S = aMesh->IndexToShape( node->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 ( pos ) + { + bool toCheck = true; + uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck ); + } + // compute not existing UV + bool project = ( posType == SMDS_TOP_3DSPACE ); + // 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; + gp_Pnt pNode = SMESH_TNodeXYZ( node ); if ( !getClosestUV( projector, pNode, newUV )) { MESSAGE("Node Projection Failed " << node); } @@ -3260,9 +4161,9 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, 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 ) + // if ( posType != SMDS_TOP_3DSPACE ) + // dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); + // if ( dist2 < dist1 ) uv = newUV; } } @@ -3330,9 +4231,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, 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; - } + if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) + std::swap( uv1, uv2 ); // get nodes on seam and its vertices list< const SMDS_MeshNode* > seamNodes; SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes(); @@ -3382,12 +4282,14 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, 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 ) ) { + // 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 ); + double x = uvMap[ n ]->Coord( iPar ); + if ( Abs( uv1.Coord( iPar ) - x ) > + Abs( uv2.Coord( iPar ) - x )) { nodesNearSeam.insert( n ); nbUseMap2++; } @@ -3496,40 +4398,33 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // move medium nodes of quadratic elements if ( isQuadratic ) { - SMESH_MesherHelper helper( *GetMesh() ); - if ( !face.IsNull() ) - helper.SetSubShape( face ); + vector nodes; + bool checkUV; list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); - for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { - const SMDS_VtkFace* QF = - dynamic_cast (*elemIt); - if(QF && QF->IsQuadratic()) { - vector Ns; - Ns.reserve(QF->NbNodes()+1); - SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator(); - while ( anIter->more() ) - Ns.push_back( cast2Node(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(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) + { + const SMDS_MeshElement* QF = *elemIt; + if ( QF->IsQuadratic() ) + { + nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ), + SMDS_MeshElement::iterator() ); + nodes.push_back( nodes[0] ); + gp_Pnt xyz; + for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node + { + if ( !surface.IsNull() ) + { + gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV ); + gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV ); + gp_XY uv = helper.GetMiddleUV( surface, uv1, uv2 ); + xyz = surface->Value( uv.X(), uv.Y() ); } 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 ); + xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] )); } + if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol ) + // we have to move a medium node + aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() ); } } } @@ -3539,26 +4434,49 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, } -//======================================================================= -//function : isReverse -//purpose : Return true if normal of prevNodes is not co-directied with -// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). -// iNotSame is where prevNodes and nextNodes are different. -// If result is true then future volume orientation is OK -//======================================================================= - -static bool isReverse(const SMDS_MeshElement* face, - const vector& prevNodes, - const vector& nextNodes, - const int iNotSame) +namespace { + //======================================================================= + //function : isReverse + //purpose : Return true if normal of prevNodes is not co-directied with + // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). + // iNotSame is where prevNodes and nextNodes are different. + // If result is true then future volume orientation is OK + //======================================================================= - SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; - SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; - gp_XYZ extrDir( pN - pP ), faceNorm; - SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false ); + bool isReverse(const SMDS_MeshElement* face, + const vector& prevNodes, + const vector& nextNodes, + const int iNotSame) + { + + SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; + SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; + gp_XYZ extrDir( pN - pP ), faceNorm; + SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); + + return faceNorm * extrDir < 0.0; + } + + //================================================================================ + /*! + * \brief Assure that theElemSets[0] holds elements, not nodes + */ + //================================================================================ - return faceNorm * extrDir < 0.0; + void setElemsFirst( TIDSortedElemSet theElemSets[2] ) + { + if ( !theElemSets[0].empty() && + (*theElemSets[0].begin())->GetType() == SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + else if ( !theElemSets[1].empty() && + (*theElemSets[1].begin())->GetType() != SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + } } //======================================================================= @@ -3581,9 +4499,9 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, //MESSAGE("sweepElement " << nbSteps); SMESHDS_Mesh* aMesh = GetMeshDS(); - const int nbNodes = elem->NbNodes(); + const int nbNodes = elem->NbNodes(); const int nbCorners = elem->NbCornerNodes(); - SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of + SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of polyhedron creation !!! */ // Loop on elem nodes: // find new nodes and detect same nodes indices @@ -3638,7 +4556,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } else { - const vector& ind = SMDS_MeshCell::reverseSmdsOrder( baseType ); + const vector& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes ); SMDS_MeshCell::applyInterlace( ind, itNN ); SMDS_MeshCell::applyInterlace( ind, prevNod ); SMDS_MeshCell::applyInterlace( ind, nextNod ); @@ -3658,6 +4576,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } } } + else if ( elem->GetType() == SMDSAbs_Edge ) + { + // orient a new face same as adjacent one + int i1, i2; + const SMDS_MeshElement* e; + TIDSortedElemSet dummy; + if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) || + ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) || + ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 ))) + { + // there is an adjacent face, check order of nodes in it + bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 ); + if ( sameOrder ) + { + std::swap( itNN[0], itNN[1] ); + std::swap( prevNod[0], prevNod[1] ); + std::swap( nextNod[0], nextNod[1] ); + isSingleNode.swap( isSingleNode[0], isSingleNode[1] ); + if ( nbSame > 0 ) + sames[0] = 1 - sames[0]; + iNotSameNode = 1 - iNotSameNode; + } + } + } int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; if ( nbSame > 0 ) { @@ -3667,6 +4609,17 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); } + if ( baseType == SMDSEntity_Polygon ) + { + if ( nbNodes == 3 ) baseType = SMDSEntity_Triangle; + else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle; + } + else if ( baseType == SMDSEntity_Quad_Polygon ) + { + if ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle; + else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle; + } + // make new elements for (int iStep = 0; iStep < nbSteps; iStep++ ) { @@ -3763,11 +4716,11 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, 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]); + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], + prevNod[2], midlNod[1], nextNod[2] ); else // sames[0]==1 - aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1], - midlNod[0], nextNod[2], prevNod[2]); + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0], + prevNod[2], nextNod[2], midlNod[0]); } } else if ( nbDouble == 3 ) @@ -3811,7 +4764,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } break; } - case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE ---> + case SMDSEntity_Quad_Triangle: // sweep (Bi)Quadratic TRIANGLE ---> + case SMDSEntity_BiQuad_Triangle: /* ??? */ { if ( nbDouble+nbSame != 3 ) break; if(nbSame==0) { // ---> pentahedron with 15 nodes @@ -3861,7 +4815,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, midlNod[0], midlNod[1], midlNod[2], midlNod[3]); } else if(nbSame==1) { - // ---> pyramid + pentahedron - can not be created since it is needed + // ---> pyramid + pentahedron - can not be created since it is needed // additional middle node at the center of face INFOS( " Sweep for face " << elem->GetID() << " can not be created" ); return; @@ -3932,14 +4886,14 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, default: break; - } - } + } // switch ( baseType ) + } // scope if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism { if ( baseType != SMDSEntity_Polygon ) { - const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType); + const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes); SMDS_MeshCell::applyInterlace( ind, prevNod ); SMDS_MeshCell::applyInterlace( ind, nextNod ); SMDS_MeshCell::applyInterlace( ind, midlNod ); @@ -3964,21 +4918,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, quantities.push_back( nbNodes ); // side faces - for (int iface = 0; iface < nbNodes; iface++) + // 3--6--2 + // | | + // 7 5 + // | | + // 0--4--1 + const int iQuad = elem->IsQuadratic(); + for (int iface = 0; iface < nbNodes; iface += 1+iQuad ) { - const int prevNbNodes = polyedre_nodes.size(); - int inextface = (iface+1) % nbNodes; - polyedre_nodes.push_back( prevNod[inextface] ); - polyedre_nodes.push_back( prevNod[iface] ); - if ( prevNod[iface] != nextNod[iface] ) + const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face + int inextface = (iface+1+iQuad) % nbNodes; + int imid = (iface+1) % nbNodes; + polyedre_nodes.push_back( prevNod[inextface] ); // 0 + if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4 + polyedre_nodes.push_back( prevNod[iface] ); // 1 + if ( prevNod[iface] != nextNod[iface] ) // 1 != 2 { - if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); - polyedre_nodes.push_back( nextNod[iface] ); + if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5 + polyedre_nodes.push_back( nextNod[iface] ); // 2 } - if ( prevNod[inextface] != nextNod[inextface] ) + if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] ); // 6 + if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3 { - polyedre_nodes.push_back( nextNod[inextface] ); - if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]); + polyedre_nodes.push_back( nextNod[inextface] ); // 3 + if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7 } const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes; if ( nbFaceNodes > 2 ) @@ -3987,7 +4950,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, polyedre_nodes.resize( prevNbNodes ); } aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - } + + } // try to create a polyherdal prism if ( aNewElem ) { newElems.push_back( aNewElem ); @@ -3999,7 +4963,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, for ( iNode = 0; iNode < nbNodes; iNode++ ) prevNod[ iNode ] = nextNod[ iNode ]; - } // for steps + } // loop on steps } //======================================================================= @@ -4015,7 +4979,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, //======================================================================= void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, - TElemOfElemListMap & newElemsMap, + TTElemOfElemListMap & newElemsMap, TElemOfVecOfNnlmiMap & elemNewNodesMap, TIDSortedElemSet& elemSet, const int nbSteps, @@ -4024,25 +4988,28 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, ASSERT( newElemsMap.size() == elemNewNodesMap.size() ); SMESHDS_Mesh* aMesh = GetMeshDS(); - // Find nodes belonging to only one initial element - sweep them to get edges. + // Find nodes belonging to only one initial element - sweep them into edges. TNodeOfNodeListMapItr nList = mapNewNodes.begin(); for ( ; nList != mapNewNodes.end(); nList++ ) { const SMDS_MeshNode* node = static_cast( nList->first ); + if ( newElemsMap.count( node )) + continue; // node was extruded into edge SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); int nbInitElems = 0; const SMDS_MeshElement* el = 0; SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only while ( eIt->more() && nbInitElems < 2 ) { - el = eIt->next(); - SMDSAbs_ElementType type = el->GetType(); + const SMDS_MeshElement* e = eIt->next(); + SMDSAbs_ElementType type = e->GetType(); if ( type == SMDSAbs_Volume || type < highType ) continue; if ( type > highType ) { nbInitElems = 0; highType = type; } + el = e; nbInitElems += elemSet.count(el); } if ( nbInitElems < 2 ) { @@ -4058,7 +5025,9 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // 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(); + ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace; + + TTElemOfElemListMap::iterator itElem = newElemsMap.begin(); TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) { @@ -4076,7 +5045,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, vecNewNodes[ 1 ]->second.back())) { myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back())); - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } else { @@ -4086,7 +5055,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back(), vecNewNodes[ 2 ]->second.back())); - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } } @@ -4108,19 +5077,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, 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 )) { + // check if a link n1-n2 is free + if ( ! SMESH_MeshAlgos::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 )); // free link edge + // make a new edge and a ceiling for a new edge + const SMDS_MeshElement* edge; + if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) { + myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge srcElements.Append( myLastCreatedElems.Last() ); } n1 = vecNewNodes[ iNode ]->second.back(); n2 = vecNewNodes[ iNext ]->second.back(); if ( !aMesh->FindEdge( n1, n2 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge - srcElements.Append( myLastCreatedElems.Last() ); + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling + srcElements.Append( edge ); } } } @@ -4134,22 +5104,22 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first; // check if a link is free - if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) && - ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) && - ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) { + if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) && + ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) && + ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) { hasFreeLinks = true; // make an edge and a ceiling for a new edge // find medium node if ( !aMesh->FindEdge( n1, n2, n3 )) { myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } 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 )); // ceiling edge - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } } @@ -4160,15 +5130,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // sweep free links into faces - if ( hasFreeLinks ) { + if ( hasFreeLinks ) { list & newVolumes = itElem->second; int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps; set initNodeSet, topNodeSet, faceNodeSet; + set initNodeSetNoCenter/*, topNodeSetNoCenter*/; for ( iNode = 0; iNode < nbNodes; iNode++ ) { initNodeSet.insert( vecNewNodes[ iNode ]->first ); topNodeSet .insert( vecNewNodes[ iNode ]->second.back() ); } + if ( isQuadratic && nbNodes % 2 ) { // node set for the case of a biquadratic + initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume + initNodeSetNoCenter.erase( vecNewNodes.back()->first ); + } for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) { list::iterator v = newVolumes.begin(); std::advance( v, volNb ); @@ -4184,14 +5159,17 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, { if ( nbSteps == 1 && faceNodeSet == topNodeSet ) continue; + if ( faceNodeSet == initNodeSetNoCenter ) + continue; freeInd.push_back( iF ); // find source edge of a free face iF vector commonNodes; // shared by the initial and free faces - commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory - std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(), - initNodeSet.begin(), initNodeSet.end(), - commonNodes.begin()); - if ( (*v)->IsQuadratic() ) + vector::iterator lastCommom; + commonNodes.resize( nbNodes, 0 ); + lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(), + initNodeSet.begin(), initNodeSet.end(), + commonNodes.begin()); + if ( std::distance( commonNodes.begin(), lastCommom ) == 3 ) srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2])); else srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1])); @@ -4207,10 +5185,11 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( freeInd.empty() ) continue; - // create faces for all steps; + // create wall faces for all steps; // if such a face has been already created by sweep of edge, // assure that its orientation is OK - for ( int iStep = 0; iStep < nbSteps; iStep++ ) { + for ( int iStep = 0; iStep < nbSteps; iStep++ ) + { vTool.Set( *v, /*ignoreCentralNodes=*/false ); vTool.SetExternalNormal(); const int nextShift = vTool.IsForward() ? +1 : -1; @@ -4337,7 +5316,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn ); else - AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4); + AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() )); } } @@ -4356,56 +5335,32 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // Make a ceiling face with a normal external to a volume + // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false ); - int iF = lastVol.GetFaceIndex( aFaceLastNodes ); - if ( iF >= 0 ) { + + if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic + aFaceLastNodes.erase( vecNewNodes.back()->second.back() ); + iF = lastVol.GetFaceIndex( aFaceLastNodes ); + } + if ( iF >= 0 ) + { lastVol.SetExternalNormal(); const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); - int nbn = lastVol.NbFaceNodes( iF ); - if ( nbn == 3 ) { - if (!hasFreeLinks || - !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ])) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); - } - else if ( nbn == 4 ) - { - if (!hasFreeLinks || - !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ])) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ])); - } - else if ( nbn == 6 && isQuadratic ) - { - if (!hasFreeLinks || - !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5])); - } - else if ( nbn == 8 && isQuadratic ) - { - if (!hasFreeLinks || - !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7]) ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7])); - } - else if ( nbn == 9 && isQuadratic ) + const int nbn = lastVol.NbFaceNodes( iF ); + vector nodeVec( nodes, nodes+nbn ); + if ( !hasFreeLinks || + !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) ) { - if (!hasFreeLinks || - !aMesh->FindElement(vector( nodes, nodes+nbn ), - SMDSAbs_Face, /*noMedium=*/false) ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7], - nodes[8])); - } - else { - vector polygon_nodes ( nodes, nodes + nbn ); - if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes)) - myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); - } + const vector& interlace = + SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn ); + SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec ); - while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( myLastCreatedElems.Last() ); + AddElement( nodeVec, anyFace.Init( elem )); + + while ( srcElements.Length() < myLastCreatedElems.Length() ) + srcElements.Append( elem ); + } } } // loop on swept elements } @@ -4416,7 +5371,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, +SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], const gp_Ax1& theAxis, const double theAngle, const int theNbSteps, @@ -4443,89 +5398,94 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, TNodeOfNodeListMap mapNewNodes; TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; + TTElemOfElemListMap newElemsMap; const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC) + myMesh->NbVolumes(ORDER_QUADRATIC) ); - // loop on theElems + // loop on theElemSets + setElemsFirst( theElemSets ); TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* node = cast2Node( itN->next() ); - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + double coord[3]; + aXYZ.Coord( coord[0], coord[1], coord[2] ); + bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); - TNodeOfNodeListMapItr nIt = - mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - if ( listNewNodes.empty() ) - { - // check if we are to create medium nodes between corner ones - bool needMediumNodes = false; - if ( isQuadraticMesh ) + // check if a node has been already sweeped + TNodeOfNodeListMapItr nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while (it->more() && !needMediumNodes ) + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) { - const SMDS_MeshElement* invElem = it->next(); - if ( invElem != elem && !theElems.count( invElem )) continue; - needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); - if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) - needMediumNodes = true; + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } } - } - // make new nodes - const SMDS_MeshNode * newNode = node; - for ( int i = 0; i < theNbSteps; i++ ) { - if ( !isOnAxis ) { - if ( needMediumNodes ) // create a medium node - { - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + // make new nodes + const SMDS_MeshNode * newNode = node; + for ( int i = 0; i < theNbSteps; i++ ) { + if ( !isOnAxis ) { + if ( needMediumNodes ) // create a medium node + { + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + } + else { + aTrsf.Transforms( coord[0], coord[1], coord[2] ); + } + // create a corner node newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); listNewNodes.push_back( newNode ); - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); } else { - aTrsf.Transforms( coord[0], coord[1], coord[2] ); + listNewNodes.push_back( newNode ); + // if ( needMediumNodes ) + // listNewNodes.push_back( newNode ); } - // create a corner node - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - else { - listNewNodes.push_back( newNode ); - // if ( needMediumNodes ) - // listNewNodes.push_back( newNode ); } } + newNodesItVec.push_back( nIt ); } - newNodesItVec.push_back( nIt ); + // make new elements + sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); } if ( theMakeWalls ) - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems ); PGroupIDs newGroupIDs; if ( theMakeGroups ) @@ -4534,50 +5494,328 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, return newGroupIDs; } +//======================================================================= +//function : ExtrusParam +//purpose : standard construction +//======================================================================= + +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep, + const int theNbSteps, + const int theFlags, + const double theTolerance): + myDir( theStep ), + myFlags( theFlags ), + myTolerance( theTolerance ), + myElemsToUse( NULL ) +{ + mySteps = new TColStd_HSequenceOfReal; + const double stepSize = theStep.Magnitude(); + for (int i=1; i<=theNbSteps; i++ ) + mySteps->Append( stepSize ); + + if (( theFlags & EXTRUSION_FLAG_SEW ) && + ( theTolerance > 0 )) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir; + } +} + +//======================================================================= +//function : ExtrusParam +//purpose : steps are given explicitly +//======================================================================= + +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir& theDir, + Handle(TColStd_HSequenceOfReal) theSteps, + const int theFlags, + const double theTolerance): + myDir( theDir ), + mySteps( theSteps ), + myFlags( theFlags ), + myTolerance( theTolerance ), + myElemsToUse( NULL ) +{ + if (( theFlags & EXTRUSION_FLAG_SEW ) && + ( theTolerance > 0 )) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir; + } +} //======================================================================= -//function : CreateNode -//purpose : +//function : ExtrusParam +//purpose : for extrusion by normal +//======================================================================= + +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize, + const int theNbSteps, + const int theFlags, + const int theDim ): + myDir( 1,0,0 ), + mySteps( new TColStd_HSequenceOfReal ), + myFlags( theFlags ), + myTolerance( 0 ), + myElemsToUse( NULL ) +{ + for (int i = 0; i < theNbSteps; i++ ) + mySteps->Append( theStepSize ); + + if ( theDim == 1 ) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D; + } +} + +//======================================================================= +//function : ExtrusParam::SetElementsToUse +//purpose : stores elements to use for extrusion by normal, depending on +// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag +//======================================================================= + +void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems ) +{ + myElemsToUse = ToUseInpElemsOnly() ? & elems : 0; +} + +//======================================================================= +//function : ExtrusParam::beginStepIter +//purpose : prepare iteration on steps //======================================================================= -const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x, - const double y, - const double z, - const double tolnode, - SMESH_SequenceOfNode& aNodes) + +void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes ) { - // myLastCreatedElems.Clear(); - // myLastCreatedNodes.Clear(); + myWithMediumNodes = withMediumNodes; + myNextStep = 1; + myCurSteps.clear(); +} +//======================================================================= +//function : ExtrusParam::moreSteps +//purpose : are there more steps? +//======================================================================= - gp_Pnt P1(x,y,z); - SMESHDS_Mesh * aMesh = myMesh->GetMeshDS(); +bool SMESH_MeshEditor::ExtrusParam::moreSteps() +{ + return myNextStep <= mySteps->Length() || !myCurSteps.empty(); +} +//======================================================================= +//function : ExtrusParam::nextStep +//purpose : returns the next step +//======================================================================= - // 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)Length() ) + { + myCurSteps.push_back( mySteps->Value( myNextStep )); + ++myNextStep; + if ( myWithMediumNodes ) + { + myCurSteps.back() /= 2.; + myCurSteps.push_back( myCurSteps.back() ); } + res = nextStep(); } - else { - SMDS_NodeIteratorPtr itn = aMesh->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) & newNodes, + const bool makeMediumNodes) +{ + gp_XYZ p = SMESH_TNodeXYZ( srcNode ); + + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + p += myDir.XYZ() * nextStep(); + const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); + newNodes.push_back( newNode ); + } + return nbNodes; +} + +//======================================================================= +//function : ExtrusParam::makeNodesByDirAndSew +//purpose : create nodes for standard extrusion with sewing +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByDirAndSew( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + gp_XYZ P1 = SMESH_TNodeXYZ( srcNode ); + + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + P1 += myDir.XYZ() * nextStep(); + + // try to search in sequence of existing nodes + // if myNodes.Length()>0 we 'nave to use given sequence + // else - use all nodes of mesh + const SMDS_MeshNode * node = 0; + if ( myNodes.Length() > 0 ) { + int i; + for(i=1; i<=myNodes.Length(); i++) { + gp_XYZ P2 = SMESH_TNodeXYZ( myNodes.Value(i) ); + if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) + { + node = myNodes.Value(i); + break; + } + } + } + else { + SMDS_NodeIteratorPtr itn = mesh->nodesIterator(); + while(itn->more()) { + SMESH_TNodeXYZ P2( itn->next() ); + if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) + { + node = P2._node; + break; + } + } + } + + if ( !node ) + node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() ); + + newNodes.push_back( node ); + + } // loop on steps + + return nbNodes; +} + +//======================================================================= +//function : ExtrusParam::makeNodesByNormal2D +//purpose : create nodes for extrusion using normals of faces +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByNormal2D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ); + + gp_XYZ p = SMESH_TNodeXYZ( srcNode ); + + // get normals to faces sharing srcNode + vector< gp_XYZ > norms, baryCenters; + gp_XYZ norm, avgNorm( 0,0,0 ); + SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( myElemsToUse && !myElemsToUse->count( face )) + continue; + if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true )) + { + norms.push_back( norm ); + avgNorm += norm; + if ( !alongAvgNorm ) + { + gp_XYZ bc(0,0,0); + int nbN = 0; + for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN ) + bc += SMESH_TNodeXYZ( nIt->next() ); + baryCenters.push_back( bc / nbN ); + } } } - // create new node and return it - const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z); - //myLastCreatedNodes.Append(NewNode); - return NewNode; + if ( norms.empty() ) return 0; + + double normSize = avgNorm.Modulus(); + if ( normSize < std::numeric_limits::min() ) + return 0; + + if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm + { + myDir = avgNorm; + return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes ); + } + + avgNorm /= normSize; + + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + gp_XYZ pNew = p; + double stepSize = nextStep(); + + if ( norms.size() > 1 ) + { + for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces + { + // translate plane of a face + baryCenters[ iF ] += norms[ iF ] * stepSize; + + // find point of intersection of the face plane located at baryCenters[ iF ] + // and avgNorm located at pNew + double d = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0 + double dot = ( norms[ iF ] * avgNorm ); + if ( dot < std::numeric_limits::min() ) + dot = stepSize * 1e-3; + double step = -( norms[ iF ] * pNew + d ) / dot; + pNew += step * avgNorm; + } + } + else + { + pNew += stepSize * avgNorm; + } + p = pNew; + + const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); + newNodes.push_back( newNode ); + } + return nbNodes; } +//======================================================================= +//function : ExtrusParam::makeNodesByNormal1D +//purpose : create nodes for extrusion using normals of edges +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByNormal1D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + throw SALOME_Exception("Extrusion 1D by Normal not implemented"); + return 0; +} //======================================================================= //function : ExtrusionSweep @@ -4585,24 +5823,15 @@ const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, - const gp_Vec& theStep, - const int theNbSteps, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance) +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElems[2], + const gp_Vec& theStep, + const int theNbSteps, + TTElemOfElemListMap& newElemsMap, + const int theFlags, + const double theTolerance) { - 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()); - - return - ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance); + ExtrusParam aParams( theStep, theNbSteps, theFlags, theTolerance ); + return ExtrusionSweep( theElems, aParams, newElemsMap ); } @@ -4612,12 +5841,9 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, - ExtrusParam& theParams, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance) +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2], + ExtrusParam& theParams, + TTElemOfElemListMap& newElemsMap) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -4627,7 +5853,9 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, SMESHDS_Mesh* aMesh = GetMeshDS(); - int nbsteps = theParams.mySteps->Length(); + setElemsFirst( theElemSets ); + const int nbSteps = theParams.NbSteps(); + theParams.SetElementsToUse( theElemSets[0] ); TNodeOfNodeListMap mapNewNodes; //TNodeOfNodeVecMap mapNewNodes; @@ -4639,91 +5867,75 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, myMesh->NbVolumes(ORDER_QUADRATIC) ); // loop on theElems TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + // check element type + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + const size_t nbNodes = elem->NbNodes(); + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( nbNodes ); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); - TNodeOfNodeListMap::iterator nIt = - mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - if ( listNewNodes.empty() ) + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { - // make new nodes - - // check if we are to create medium nodes between corner ones - bool needMediumNodes = false; - if ( isQuadraticMesh ) + // check if a node has been already sweeped + const SMDS_MeshNode* node = cast2Node( itN->next() ); + TNodeOfNodeListMap::iterator nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while (it->more() && !needMediumNodes ) - { - const SMDS_MeshElement* invElem = it->next(); - if ( invElem != elem && !theElems.count( invElem )) continue; - needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); - if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) - needMediumNodes = true; - } - } + // make new nodes - double coord[] = { node->X(), node->Y(), node->Z() }; - for ( int i = 0; i < nbsteps; i++ ) - { - if ( needMediumNodes ) // create a medium node + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) { - 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 ); + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z); - myLastCreatedNodes.Append(newNode); + } + // create nodes for all steps + if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes )) + { + list::iterator newNodesIt = listNewNodes.begin(); + for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt ) + { + myLastCreatedNodes.Append( *newNodesIt ); srcNodes.Append( node ); - listNewNodes.push_back( newNode ); } } - // create a corner node - coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2], - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); + else + { + break; // newNodesItVec will be shorter than nbNodes } } + newNodesItVec.push_back( nIt ); } - newNodesItVec.push_back( nIt ); + // make new elements + if ( newNodesItVec.size() == nbNodes ) + sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems ); } - if( theFlags & EXTRUSION_FLAG_BOUNDARY ) { - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems ); + if ( theParams.ToMakeBoundary() ) { + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems ); } PGroupIDs newGroupIDs; - if ( theMakeGroups ) + if ( theParams.ToMakeGroups() ) newGroupIDs = generateGroups( srcNodes, srcElems, "extruded"); return newGroupIDs; @@ -4734,7 +5946,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, //purpose : //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_subMesh* theTrack, const SMDS_MeshNode* theN1, const bool theHasAngles, @@ -4763,7 +5975,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TNodeOfNodeListMap mapNewNodes; // 1. Check data - aNbE = theElements.size(); + aNbE = theElements[0].size() + theElements[1].size(); // nothing to do if ( !aNbE ) return EXTR_NO_ELEMENTS; @@ -4789,7 +6001,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, if( aS.ShapeType() == TopAbs_EDGE ) { aTrackEdge = TopoDS::Edge( aS ); // the Edge must not be degenerated - if ( BRep_Tool::Degenerated( aTrackEdge ) ) + if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) return EXTR_BAD_PATH_SHAPE; TopExp::Vertices( aTrackEdge, aV1, aV2 ); aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); @@ -4822,7 +6034,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, list< list > LLPPs; int startNid = theN1->GetID(); TColStd_MapOfInteger UsedNums; - + int NbEdges = Edges.Length(); int i = 1; for(; i<=NbEdges; i++) { @@ -4906,7 +6118,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, //purpose : //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_Mesh* theTrack, const SMDS_MeshNode* theN1, const bool theHasAngles, @@ -4934,7 +6146,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TNodeOfNodeListMap mapNewNodes; // 1. Check data - aNbE = theElements.size(); + aNbE = theElements[0].size() + theElements[1].size(); // nothing to do if ( !aNbE ) return EXTR_NO_ELEMENTS; @@ -4957,7 +6169,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, const TopoDS_Shape& aS = theTrack->GetShapeToMesh(); - if( aS == SMESH_Mesh::PseudoShape() ) { + if ( !theTrack->HasShapeToMesh() ) { //Mesh without shape const SMDS_MeshNode* currentNode = NULL; const SMDS_MeshNode* prevNode = theN1; @@ -4973,9 +6185,9 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, if( !theTrack->GetMeshDS()->Contains(theN1) ) { return EXTR_BAD_STARTING_NODE; } - + conn = nbEdgeConnectivity(theN1); - if(conn > 2) + if( conn != 1 ) return EXTR_PATH_NOT_EDGE; aItE = theN1->GetInverseElementIterator(); @@ -4988,14 +6200,14 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, if(currentNode == prevNode) currentNode = static_cast(nIt->next()); aNodesList.push_back(currentNode); - } else { + } else { nIt = currentElem->nodesIterator(); while( nIt->more() ) { currentNode = static_cast(nIt->next()); if(currentNode == prevNode) currentNode = static_cast(nIt->next()); aNodesList.push_back(currentNode); - + //case of the closed mesh if(currentNode == theN1) { nbEdges++; @@ -5004,7 +6216,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, conn = nbEdgeConnectivity(currentNode); if(conn > 2) { - return EXTR_PATH_NOT_EDGE; + return EXTR_PATH_NOT_EDGE; }else if( conn == 1 && nbEdges > 0 ) { //End of the path nbEdges++; @@ -5020,8 +6232,8 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, nbEdges++; } } - } - + } + if(nbEdges != totalNbEdges) return EXTR_PATH_NOT_EDGE; @@ -5033,7 +6245,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X(); y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y(); z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z(); - TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2)); + TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2)); list LPP; aPrms.clear(); MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); @@ -5072,18 +6284,16 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, fullList.pop_back(); } fullList.push_back(PP1); - + } // Sub-shape for the Pattern must be an Edge or Wire else if( aS.ShapeType() == TopAbs_EDGE ) { aTrackEdge = TopoDS::Edge( aS ); // the Edge must not be degenerated - if ( BRep_Tool::Degenerated( aTrackEdge ) ) + if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) return EXTR_BAD_PATH_SHAPE; TopExp::Vertices( aTrackEdge, aV1, aV2 ); - aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN1 = aItN->next(); - aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN2 = aItN->next(); + const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS ); + const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS ); // starting node must be aN1 or aN2 if ( !( aN1 == theN1 || aN2 == theN1 ) ) return EXTR_BAD_STARTING_NODE; @@ -5105,7 +6315,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TopExp_Explorer eExp(aS, TopAbs_EDGE); for(; eExp.More(); eExp.Next()) { TopoDS_Edge E = TopoDS::Edge( eExp.Current() ); - if( BRep_Tool::Degenerated(E) ) continue; + if( SMESH_Algo::isDegenerated(E) ) continue; SMESH_subMesh* SM = theTrack->GetSubMesh(E); if(SM) { LSM.push_back(SM); @@ -5113,7 +6323,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, } } list< list > LLPPs; - int startNid = theN1->GetID(); + TopoDS_Vertex aVprev; TColStd_MapOfInteger UsedNums; int NbEdges = Edges.Length(); int i = 1; @@ -5127,17 +6337,28 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, SMESH_subMesh* locTrack = *itLSM; SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS(); TopExp::Vertices( aTrackEdge, aV1, aV2 ); - aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN1 = aItN->next(); - aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN2 = aItN->next(); - // starting node must be aN1 or aN2 - if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue; + bool aN1isOK = false, aN2isOK = false; + if ( aVprev.IsNull() ) { + // if previous vertex is not yet defined, it means that we in the beginning of wire + // and we have to find initial vertex corresponding to starting node theN1 + const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS ); + const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS ); + // starting node must be aN1 or aN2 + aN1isOK = ( aN1 && aN1 == theN1 ); + aN2isOK = ( aN2 && aN2 == theN1 ); + } + else { + // we have specified ending vertex of the previous edge on the previous iteration + // and we have just to check that it corresponds to any vertex in current segment + aN1isOK = aVprev.IsSame( aV1 ); + aN2isOK = aVprev.IsSame( aV2 ); + } + if ( !aN1isOK && !aN2isOK ) continue; // 2. Collect parameters on the track edge aPrms.clear(); aItN = locMeshDS->GetNodes(); while ( aItN->more() ) { - const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_MeshNode* pNode = aItN->next(); const SMDS_EdgePosition* pEPos = static_cast( pNode->GetPosition() ); double aT = pEPos->GetUParameter(); @@ -5145,38 +6366,31 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, } list LPP; //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); + MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP); LLPPs.push_back(LPP); UsedNums.Add(k); // update startN for search following egde - if( aN1->GetID() == startNid ) startNid = aN2->GetID(); - else startNid = aN1->GetID(); + if ( aN1isOK ) aVprev = aV2; + else aVprev = aV1; break; } } list< list >::iterator itLLPP = LLPPs.begin(); - list firstList = *itLLPP; - list::iterator itPP = firstList.begin(); - for(; itPP!=firstList.end(); itPP++) { - fullList.push_back( *itPP ); - } + list& firstList = *itLLPP; + fullList.splice( fullList.end(), firstList ); + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); fullList.pop_back(); itLLPP++; for(; itLLPP!=LLPPs.end(); itLLPP++) { - list currList = *itLLPP; - itPP = currList.begin(); + list& currList = *itLLPP; SMESH_MeshEditor_PathPoint PP2 = currList.front(); gp_Dir D1 = PP1.Tangent(); gp_Dir D2 = PP2.Tangent(); - gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2, - (D1.Z()+D2.Z())/2 ) ); + gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 ); PP1.SetTangent(Dnew); fullList.push_back(PP1); - itPP++; - for(; itPP!=currList.end(); itPP++) { - fullList.push_back( *itPP ); - } + fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() ); PP1 = fullList.back(); fullList.pop_back(); } @@ -5198,9 +6412,9 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, //purpose : auxilary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, - const TopoDS_Edge& aTrackEdge, - bool FirstIsStart, +SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, + const TopoDS_Edge& aTrackEdge, + bool FirstIsStart, list& LPP) { Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; @@ -5253,236 +6467,211 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, //purpose : auxilary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements, +SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2], list& fullList, - const bool theHasAngles, - list& theAngles, - const bool theLinearVariation, - const bool theHasRefPoint, - const gp_Pnt& theRefPoint, - const bool theMakeGroups) + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) { - MESSAGE("MakeExtrElements"); - //cout<<"MakeExtrElements fullList.size() = "< aPPs(aNbTP); + const int aNbTP = fullList.size(); // Angles - if( theHasAngles && theAngles.size()>0 && theLinearVariation ) { + if( theHasAngles && !theAngles.empty() && theLinearVariation ) LinearAngleVariation(aNbTP-1, theAngles); - } - vector aAngles( aNbTP ); - int j = 0; - for(; j::iterator aItD = theAngles.begin(); - for ( j=1; (aItD != theAngles.end()) && (j aPPs; list::iterator itPP = fullList.begin(); - for(; itPP!=fullList.end(); itPP++) { - j++; - SMESH_MeshEditor_PathPoint PP = *itPP; - PP.SetAngle(aAngles[j]); - aPPs[j] = PP; + list::iterator itAngles = theAngles.begin(); + aPPs.push_back( *itPP++ ); + for( ; itPP != fullList.end(); itPP++) { + aPPs.push_back( *itPP ); + if ( theHasAngles && itAngles != theAngles.end() ) + aPPs.back().SetAngle( *itAngles++ ); } - TNodeOfNodeListMap mapNewNodes; + TNodeOfNodeListMap mapNewNodes; TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; + TTElemOfElemListMap newElemsMap; TIDSortedElemSet::iterator itElem; - double aX, aY, aZ; - int aNb; - SMDSAbs_ElementType aTypeE; // source elements for each generated one SMESH_SequenceOfElemPtr srcElems, srcNodes; // 3. Center of rotation aV0 gp_Pnt aV0 = theRefPoint; - gp_XYZ aGC; - if ( !theHasRefPoint ) { - aNb = 0; - aGC.SetCoord( 0.,0.,0. ); - - itElem = theElements.begin(); - for ( ; itElem != theElements.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; + if ( !theHasRefPoint ) + { + gp_XYZ aGC( 0.,0.,0. ); + TIDSortedElemSet newNodes; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = static_cast( itN->next() ); - aX = node->X(); - aY = node->Y(); - aZ = node->Z(); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + itElem = theElements.begin(); + for ( ; itElem != theElements.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; - if ( mapNewNodes.find( node ) == mapNewNodes.end() ) { - list aLNx; - mapNewNodes[node] = aLNx; - // - gp_XYZ aXYZ( aX, aY, aZ ); - aGC += aXYZ; - ++aNb; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { + const SMDS_MeshElement* node = itN->next(); + if ( newNodes.insert( node ).second ) + aGC += SMESH_TNodeXYZ( node ); } } } - aGC /= aNb; + aGC /= newNodes.size(); aV0.SetXYZ( aGC ); } // if (!theHasRefPoint) { - mapNewNodes.clear(); // 4. Processing the elements SMESHDS_Mesh* aMesh = GetMeshDS(); - for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - aTypeE = elem->GetType(); - if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) ) - continue; - - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); - - // loop on elem nodes - int nodeIndex = -1; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - ++nodeIndex; - // check if a node has been already processed - 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; - gp_Dir aDT1x, aDT0x, aDT1T0; - - aTolAng=1.e-4; - - aV0x = aV0; - aPN0.SetCoord(aX, aY, aZ); - - const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; - aP0x = aPP0.Pnt(); - aDT0x= aPP0.Tangent(); - //cout<<"j = 0 PP: Pnt("<GetType(); + // if ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) + // continue; - // rotation 1 [ T1,T0 ] - aAngleT1T0=-aDT1x.Angle( aDT0x ); - if (fabs(aAngleT1T0) > aTolAng) { - aDT1T0=aDT1x^aDT0x; - anAxT1T0.SetLocation( aV1x ); - anAxT1T0.SetDirection( aDT1T0 ); - aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); - } + // loop on elem nodes + int nodeIndex = -1; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + ++nodeIndex; + // check if a node has been already processed + 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 + Standard_Real aAngle1x, aAngleT1T0, aTolAng; + gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; + gp_Ax1 anAx1, anAxT1T0; + gp_Dir aDT1x, aDT0x, aDT1T0; + + aTolAng=1.e-4; + + aV0x = aV0; + aPN0 = SMESH_TNodeXYZ( node ); + + const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; + aP0x = aPP0.Pnt(); + aDT0x= aPP0.Tangent(); + //cout<<"j = 0 PP: Pnt("< aTolAng) { + aDT1T0=aDT1x^aDT0x; + anAxT1T0.SetLocation( aV1x ); + anAxT1T0.SetDirection( aDT1T0 ); + aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); + + aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); + } - // rotation 2 - if ( theHasAngles ) { - anAx1.SetLocation( aV1x ); - anAx1.SetDirection( aDT1x ); - aTrsfRot.SetRotation( anAx1, aAngle1x ); + // rotation 2 + if ( theHasAngles ) { + anAx1.SetLocation( aV1x ); + anAx1.SetDirection( aDT1x ); + aTrsfRot.SetRotation( anAx1, aAngle1x ); - aPN1 = aPN1.Transformed( aTrsfRot ); - } + aPN1 = aPN1.Transformed( aTrsfRot ); + } - // make new node - //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(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); + // make new node + //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(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); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + } + const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); listNewNodes.push_back( newNode ); - } - aX = aPN1.X(); - aY = aPN1.Y(); - aZ = aPN1.Z(); - const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - aPN0 = aPN1; - aP0x = aP1x; - aV0x = aV1x; - aDT0x = aDT1x; + 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); - srcNodes.Append( node ); - 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]); + 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); + srcNodes.Append( node ); + 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 ); + newNodesItVec.push_back( nIt ); + } + // make new elements + //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], + // newNodesItVec[0]->second.size(), myLastCreatedElems ); + sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } - // make new elements - //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], - // newNodesItVec[0]->second.size(), myLastCreatedElems ); - sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems ); if ( theMakeGroups ) generateGroups( srcNodes, srcElems, "extruded"); @@ -5601,10 +6790,12 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, groupPostfix = "transformed"; } - SMESH_MeshEditor targetMeshEditor( theTargetMesh ); SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; SMESHDS_Mesh* aMesh = GetMeshDS(); + SMESH_MeshEditor targetMeshEditor( theTargetMesh ); + SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0; + SMESH_MeshEditor::ElemFeatures elemType; // map old node to new one TNodeNodeMap nodeMap; @@ -5636,70 +6827,68 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, // loop on elements to transform nodes : first orphan nodes then elems TIDSortedElemSet::iterator itElem; - TIDSortedElemSet *elements[] = {&orphanNode, &theElems }; + TIDSortedElemSet *elements[] = { &orphanNode, &theElems }; for (int i=0; i<2; i++) - for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem ) - continue; - - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - - const SMDS_MeshNode* node = cast2Node( itN->next() ); - // check if a node has been already transformed - pair n2n_isnew = - nodeMap.insert( make_pair ( node, node )); - if ( !n2n_isnew.second ) + for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + if ( !elem ) continue; + // loop on elem nodes double coord[3]; - coord[0] = node->X(); - coord[1] = node->Y(); - coord[2] = node->Z(); - theTrsf.Transforms( coord[0], coord[1], coord[2] ); - if ( theTargetMesh ) { - const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else if ( theCopy ) { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - 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() ); - } + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* node = cast2Node( itN->next() ); + // check if a node has been already transformed + pair n2n_isnew = + nodeMap.insert( make_pair ( node, node )); + if ( !n2n_isnew.second ) + continue; - // keep inverse elements - if ( !theCopy && !theTargetMesh && needReverse ) { - SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); - while ( invElemIt->more() ) { - const SMDS_MeshElement* iel = invElemIt->next(); - inverseElemSet.insert( iel ); + node->GetXYZ( coord ); + theTrsf.Transforms( coord[0], coord[1], coord[2] ); + if ( theTargetMesh ) { + const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + } + else if ( theCopy ) { + const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + } + 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() ); + } + + // keep inverse elements + if ( !theCopy && !theTargetMesh && needReverse ) { + SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); + while ( invElemIt->more() ) { + const SMDS_MeshElement* iel = invElemIt->next(); + inverseElemSet.insert( iel ); + } } } - } - } + } // loop on elems in { &orphanNode, &theElems }; // either create new elements or reverse mirrored ones if ( !theCopy && !needReverse && !theTargetMesh ) return PGroupIDs(); - TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin(); - for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) - theElems.insert( *invElemIt ); + theElems.insert( inverseElemSet.begin(),inverseElemSet.end() ); // Replicate or reverse elements std::vector iForw; + vector nodes; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { const SMDS_MeshElement* elem = *itElem; @@ -5707,125 +6896,47 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, SMDSAbs_GeometryType geomType = elem->GetGeomType(); int nbNodes = elem->NbNodes(); - if ( geomType == SMDSGeom_POINT ) continue; // node + if ( geomType == SMDSGeom_NONE ) continue; // node - switch ( geomType ) { + nodes.resize( nbNodes ); - case SMDSGeom_POLYGON: // ---------------------- polygon + if ( geomType == SMDSGeom_POLYHEDRA ) // ------------------ polyhedral volume + { + const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem ); + if (!aPolyedre) + continue; + nodes.clear(); + bool allTransformed = true; + int nbFaces = aPolyedre->NbFaces(); + for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - vector poly_nodes (nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while (itN->more()) { - const SMDS_MeshNode* node = - static_cast(itN->next()); + 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()) - break; // not all nodes transformed - if (needReverse) { - // reverse mirrored faces and volumes - poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; - } else { - poly_nodes[iNode] = (*nodeMapIt).second; - } - iNode++; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolygonNodes(elem, poly_nodes); - } - } - break; - - case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume - { - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( elem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - continue; - } - - vector poly_nodes; poly_nodes.reserve( nbNodes ); - vector quantities; quantities.reserve( nbNodes ); - - bool allTransformed = true; - int nbFaces = aPolyedre->NbFaces(); - for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { - const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) { - allTransformed = false; // not all nodes transformed - } else { - poly_nodes.push_back((*nodeMapIt).second); - } - if ( needReverse && allTransformed ) - std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() ); - } - quantities.push_back(nbFaceNodes); - } - if ( !allTransformed ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - } - } - break; - - case SMDSGeom_BALL: // -------------------- Ball - { - if ( !theCopy && !theTargetMesh ) continue; - - TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) ); - if (nodeMapIt == nodeMap.end()) - continue; // not all nodes transformed - - double diameter = static_cast(elem)->GetDiameter(); - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter )); - srcElems.Append( elem ); - } - else { - myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter )); - srcElems.Append( elem ); + if ( nodeMapIt == nodeMap.end() ) + allTransformed = false; // not all nodes transformed + else + nodes.push_back((*nodeMapIt).second); } + if ( needReverse && allTransformed ) + std::reverse( nodes.end() - nbFaceNodes, nodes.end() ); } - break; - - default: // ----------------------- Regular elements - + if ( !allTransformed ) + continue; // not all nodes transformed + } + else // ----------------------- the rest element types + { while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() ); - const std::vector& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() ); - const std::vector& i = needReverse ? iRev : iForw; + const vector& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes ); + const vector& i = needReverse ? iRev : iForw; // find transformed nodes - vector nodes(nbNodes); int iNode = 0; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - const SMDS_MeshNode* node = - static_cast( itN->next() ); + const SMDS_MeshNode* node = static_cast( itN->next() ); TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); if ( nodeMapIt == nodeMap.end() ) break; // not all nodes transformed @@ -5833,32 +6944,29 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, } if ( iNode != nbNodes ) continue; // not all nodes transformed + } - if ( theTargetMesh ) { - if ( SMDS_MeshElement* copy = - targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); - } - } - else if ( theCopy ) { - if ( AddElement( nodes, elem->GetType(), elem->IsPoly() )) - srcElems.Append( elem ); - } - else { - // reverse element as it was reversed by transformation - if ( nbNodes > 2 ) - aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); - } - } // switch ( geomType ) + if ( editor ) { + // copy in this or a new mesh + if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false ))) + srcElems.Append( elem ); + } + else { + // reverse element as it was reversed by transformation + if ( nbNodes > 2 ) + aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); + } } // loop on elements + if ( editor && editor != this ) + myLastCreatedElems = editor->myLastCreatedElems; + PGroupIDs newGroupIDs; if ( ( theMakeGroups && theCopy ) || ( theMakeGroups && theTargetMesh ) ) - newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh ); + newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false ); return newGroupIDs; } @@ -5866,9 +6974,11 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, //======================================================================= /*! * \brief Create groups of elements made during transformation - * \param nodeGens - nodes making corresponding myLastCreatedNodes - * \param elemGens - elements making corresponding myLastCreatedElems - * \param postfix - to append to names of new groups + * \param nodeGens - nodes making corresponding myLastCreatedNodes + * \param elemGens - elements making corresponding myLastCreatedElems + * \param postfix - to append to names of new groups + * \param targetMesh - mesh to create groups in + * \param topPresent - is there "top" elements that are created by sweeping */ //======================================================================= @@ -5876,40 +6986,53 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, const SMESH_SequenceOfElemPtr& elemGens, const std::string& postfix, - SMESH_Mesh* targetMesh) + SMESH_Mesh* targetMesh, + const bool topPresent) { PGroupIDs newGroupIDs( new list ); SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh(); // Sort existing groups by types and collect their names - // to store an old group and a generated new one - typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup; + // containers to store an old group and generated new ones; + // 1st new group is for result elems of different type than a source one; + // 2nd new group is for same type result elems ("top" group at extrusion) + using boost::tuple; + using boost::make_tuple; + typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup; vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes ); + vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups // group names set< string > groupNames; - // - SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0; + SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups(); - while ( groupIt->more() ) { + if ( !groupIt->more() ) return newGroupIDs; + + int newGroupID = mesh->GetGroupIds().back()+1; + while ( groupIt->more() ) + { SMESH_Group * group = groupIt->next(); if ( !group ) continue; SMESHDS_GroupBase* groupDS = group->GetGroupDS(); if ( !groupDS || groupDS->IsEmpty() ) continue; - groupNames.insert( group->GetName() ); + groupNames.insert ( group->GetName() ); groupDS->SetStoreName( group->GetName() ); - groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup )); + const SMDSAbs_ElementType type = groupDS->GetType(); + SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); + SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); + groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup )); + orderedOldNewGroups.push_back( & groupsByType[ type ].back() ); } - // Groups creation + // Loop on nodes and elements to add them in new groups - // loop on nodes and elements + vector< const SMDS_MeshElement* > resultElems; for ( int isNodes = 0; isNodes < 2; ++isNodes ) { const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems; if ( gens.Length() != elems.Length() ) - throw SALOME_Exception(LOCALIZED("invalid args")); + throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args"); // loop on created elements for (int iElem = 1; iElem <= elems.Length(); ++iElem ) @@ -5920,13 +7043,13 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, continue; } list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ]; - if ( groupsOldNew.empty() ) { + if ( groupsOldNew.empty() ) { // no groups of this type at all while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) ++iElem; // skip all elements made by sourceElem continue; } - // collect all elements made by sourceElem - list< const SMDS_MeshElement* > resultElems; + // collect all elements made by the iElem-th sourceElem + resultElems.clear(); if ( const SMDS_MeshElement* resElem = elems( iElem )) if ( resElem != sourceElem ) resultElems.push_back( resElem ); @@ -5934,1468 +7057,190 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, if ( const SMDS_MeshElement* resElem = elems( ++iElem )) if ( resElem != sourceElem ) resultElems.push_back( resElem ); - // do not generate element groups from node ones -// if ( sourceElem->GetType() == SMDSAbs_Node && -// elems( iElem )->GetType() != SMDSAbs_Node ) -// continue; - // add resultElems to groups made by ones the sourceElem belongs to + const SMDS_MeshElement* topElem = 0; + if ( isNodes ) // there must be a top element + { + topElem = resultElems.back(); + resultElems.pop_back(); + } + else + { + vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin(); + for ( ; resElemIt != resultElems.rend() ; ++resElemIt ) + if ( (*resElemIt)->GetType() == sourceElem->GetType() ) + { + topElem = *resElemIt; + *resElemIt = 0; // erase *resElemIt + break; + } + } + // add resultElems to groups originted from ones the sourceElem belongs to list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end(); for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew ) { - SMESHDS_GroupBase* oldGroup = gOldNew->first; - if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup + SMESHDS_GroupBase* oldGroup = gOldNew->get<0>(); + if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup { - SMDS_MeshGroup* & newGroup = gOldNew->second; - if ( !newGroup )// create a new group - { - // make a name - string name = oldGroup->GetStoreName(); - if ( !targetMesh ) { - name += "_"; - name += postfix; - int nb = 0; - while ( !groupNames.insert( name ).second ) // name exists - { - if ( nb == 0 ) { - name += "_1"; - } - else { - TCollection_AsciiString nbStr(nb+1); - name.resize( name.rfind('_')+1 ); - name += nbStr.ToCString(); - } - ++nb; - } - } - // make a group - int id; - SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(), - name.c_str(), id ); - SMESHDS_Group* groupDS = static_cast(group->GetGroupDS()); - newGroup = & groupDS->SMDSGroup(); - newGroupIDs->push_back( id ); - } - // fill in a new group - list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; + SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup(); + vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt ) - newGroup->Add( *resElemIt ); + if ( *resElemIt ) + newGroup.Add( *resElemIt ); + + // fill a "top" group + if ( topElem ) + { + SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup(); + newTopGroup.Add( topElem ); + } } } } // loop on created elements }// loop on nodes and elements + // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups + + list topGrouIds; + for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i ) + { + SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>(); + SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(), + orderedOldNewGroups[i]->get<2>() }; + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + SMESHDS_Group* newGroupDS = newGroups[ is2nd ]; + if ( newGroupDS->IsEmpty() ) + { + mesh->GetMeshDS()->RemoveGroup( newGroupDS ); + } + else + { + // set group type + newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() ); + + // make a name + const bool isTop = ( topPresent && + newGroupDS->GetType() == oldGroupDS->GetType() && + is2nd ); + + string name = oldGroupDS->GetStoreName(); + { // remove trailing whitespaces (issue 22599) + size_t size = name.size(); + while ( size > 1 && isspace( name[ size-1 ])) + --size; + if ( size != name.size() ) + { + name.resize( size ); + oldGroupDS->SetStoreName( name.c_str() ); + } + } + if ( !targetMesh ) { + string suffix = ( isTop ? "top": postfix.c_str() ); + name += "_"; + name += suffix; + int nb = 1; + while ( !groupNames.insert( name ).second ) // name exists + name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++; + } + else if ( isTop ) { + name += "_top"; + } + newGroupDS->SetStoreName( name.c_str() ); + + // make a SMESH_Groups + mesh->AddGroup( newGroupDS ); + if ( isTop ) + topGrouIds.push_back( newGroupDS->GetID() ); + else + newGroupIDs->push_back( newGroupDS->GetID() ); + } + } + } + newGroupIDs->splice( newGroupIDs->end(), topGrouIds ); + return newGroupIDs; } //================================================================================ /*! - * \brief Return list of group of nodes close to each other within theTolerance - * Search among theNodes or in the whole mesh if theNodes is empty using - * an Octree algorithm + * * \brief Return list of group of nodes close to each other within theTolerance + * * Search among theNodes or in the whole mesh if theNodes is empty using + * * an Octree algorithm + * \param [in,out] theNodes - the nodes to treat + * \param [in] theTolerance - the tolerance + * \param [out] theGroupsOfNodes - the result groups of coincident nodes + * \param [in] theSeparateCornersAndMedium - if \c true, in quadratic mesh puts + * corner and medium nodes in separate groups */ //================================================================================ void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes, const double theTolerance, - TListOfListOfNodes & theGroupsOfNodes) + TListOfListOfNodes & theGroupsOfNodes, + bool theSeparateCornersAndMedium) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - if ( theNodes.empty() ) - { // get all nodes in the mesh + if ( myMesh->NbEdges ( ORDER_QUADRATIC ) + + myMesh->NbFaces ( ORDER_QUADRATIC ) + + myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 ) + theSeparateCornersAndMedium = false; + + TIDSortedNodeSet& corners = theNodes; + TIDSortedNodeSet medium; + + if ( theNodes.empty() ) // get all nodes in the mesh + { + TIDSortedNodeSet* nodes[2] = { &corners, &medium }; SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true); - while ( nIt->more() ) - theNodes.insert( theNodes.end(),nIt->next()); + if ( theSeparateCornersAndMedium ) + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )]; + nodeSet->insert( nodeSet->end(), n ); + } + else + while ( nIt->more() ) + theNodes.insert( theNodes.end(),nIt->next() ); + } + else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes + { + TIDSortedNodeSet::iterator nIt = corners.begin(); + while ( nIt != corners.end() ) + if ( SMESH_MesherHelper::IsMedium( *nIt )) + { + medium.insert( medium.end(), *nIt ); + corners.erase( nIt++ ); + } + else + { + ++nIt; + } } - SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance); + if ( !corners.empty() ) + SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance ); + if ( !medium.empty() ) + SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance ); } - //======================================================================= -/*! - * \brief Implementation of search for the node closest to point - */ +//function : SimplifyFace +//purpose : split a chain of nodes into several closed chains //======================================================================= -struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher +int SMESH_MeshEditor::SimplifyFace (const vector& faceNodes, + vector& poly_nodes, + vector& quantities) const { - //--------------------------------------------------------------------- - /*! - * \brief Constructor - */ - SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh ) - { - myMesh = ( SMESHDS_Mesh* ) theMesh; + int nbNodes = faceNodes.size(); - TIDSortedNodeSet nodes; - if ( theMesh ) { - SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true); - while ( nIt->more() ) - nodes.insert( nodes.end(), nIt->next() ); - } - myOctreeNode = new SMESH_OctreeNode(nodes) ; - - // get max size of a leaf box - SMESH_OctreeNode* tree = myOctreeNode; - while ( !tree->isLeaf() ) - { - SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); - if ( cIt->more() ) - tree = cIt->next(); - } - myHalfLeafSize = tree->maxSize() / 2.; - } - - //--------------------------------------------------------------------- - /*! - * \brief Move node and update myOctreeNode accordingly - */ - void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt ) - { - myOctreeNode->UpdateByMoveNode( node, toPnt ); - myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() ); - } - - //--------------------------------------------------------------------- - /*! - * \brief Do it's job - */ - const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt ) - { - map dist2Nodes; - myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize ); - if ( !dist2Nodes.empty() ) - return dist2Nodes.begin()->second; - list nodes; - //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize ); - - double minSqDist = DBL_MAX; - if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt - { - // sort leafs by their distance from thePnt - typedef map< double, SMESH_OctreeNode* > TDistTreeMap; - TDistTreeMap treeMap; - list< SMESH_OctreeNode* > treeList; - list< SMESH_OctreeNode* >::iterator trIt; - treeList.push_back( myOctreeNode ); - - gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); - bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize ); - for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt) - { - SMESH_OctreeNode* tree = *trIt; - if ( !tree->isLeaf() ) // put children to the queue - { - if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue; - SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); - while ( cIt->more() ) - treeList.push_back( cIt->next() ); - } - else if ( tree->NbNodes() ) // put a tree to the treeMap - { - const Bnd_B3d& box = tree->getBox(); - double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() )); - pair it_in = treeMap.insert( make_pair( sqDist, tree )); - if ( !it_in.second ) // not unique distance to box center - treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree )); - } - } - // find distance after which there is no sense to check tree's - double sqLimit = DBL_MAX; - TDistTreeMap::iterator sqDist_tree = treeMap.begin(); - if ( treeMap.size() > 5 ) { - SMESH_OctreeNode* closestTree = sqDist_tree->second; - const Bnd_B3d& box = closestTree->getBox(); - double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() ); - sqLimit = limit * limit; - } - // get all nodes from trees - for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) { - if ( sqDist_tree->first > sqLimit ) - break; - SMESH_OctreeNode* tree = sqDist_tree->second; - tree->NodesAround( tree->GetNodeIterator()->next(), &nodes ); - } - } - // find closest among nodes - minSqDist = DBL_MAX; - const SMDS_MeshNode* closestNode = 0; - list::iterator nIt = nodes.begin(); - for ( ; nIt != nodes.end(); ++nIt ) { - double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) ); - if ( minSqDist > sqDist ) { - closestNode = *nIt; - minSqDist = sqDist; - } - } - return closestNode; - } - - //--------------------------------------------------------------------- - /*! - * \brief Destructor - */ - ~SMESH_NodeSearcherImpl() { delete myOctreeNode; } - - //--------------------------------------------------------------------- - /*! - * \brief Return the node tree - */ - const SMESH_OctreeNode* getTree() const { return myOctreeNode; } - -private: - SMESH_OctreeNode* myOctreeNode; - SMESHDS_Mesh* myMesh; - double myHalfLeafSize; // max size of a leaf box -}; - -//======================================================================= -/*! - * \brief Return SMESH_NodeSearcher - */ -//======================================================================= - -SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() -{ - return new SMESH_NodeSearcherImpl( GetMeshDS() ); -} - -// ======================================================================== -namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() -{ - const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree - const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152 - const double NodeRadius = 1e-9; // to enlarge bnd box of element - - //======================================================================= - /*! - * \brief Octal tree of bounding boxes of elements - */ - //======================================================================= - - class ElementBndBoxTree : public SMESH_Octree - { - public: - - ElementBndBoxTree(const SMDS_Mesh& mesh, - SMDSAbs_ElementType elemType, - SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), - double tolerance = NodeRadius ); - void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems ); - void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); - void getElementsInSphere ( const gp_XYZ& center, - const double radius, TIDSortedElemSet& foundElems); - size_t getSize() { return std::max( _size, _elements.size() ); } - ~ElementBndBoxTree(); - - protected: - ElementBndBoxTree():_size(0) {} - SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; } - void buildChildrenData(); - Bnd_B3d* buildRootBox(); - private: - //!< Bounding box of element - struct ElementBox : public Bnd_B3d - { - const SMDS_MeshElement* _element; - int _refCount; // an ElementBox can be included in several tree branches - ElementBox(const SMDS_MeshElement* elem, double tolerance); - }; - vector< ElementBox* > _elements; - size_t _size; - }; - - //================================================================================ - /*! - * \brief ElementBndBoxTree creation - */ - //================================================================================ - - ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance) - :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. )) - { - int nbElems = mesh.GetMeshInfo().NbElements( elemType ); - _elements.reserve( nbElems ); - - SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType ); - while ( elemIt->more() ) - _elements.push_back( new ElementBox( elemIt->next(),tolerance )); - - compute(); - } - - //================================================================================ - /*! - * \brief Destructor - */ - //================================================================================ - - ElementBndBoxTree::~ElementBndBoxTree() - { - for ( int i = 0; i < _elements.size(); ++i ) - if ( --_elements[i]->_refCount <= 0 ) - delete _elements[i]; - } - - //================================================================================ - /*! - * \brief Return the maximal box - */ - //================================================================================ - - Bnd_B3d* ElementBndBoxTree::buildRootBox() - { - Bnd_B3d* box = new Bnd_B3d; - for ( int i = 0; i < _elements.size(); ++i ) - box->Add( *_elements[i] ); - return box; - } - - //================================================================================ - /*! - * \brief Redistrubute element boxes among children - */ - //================================================================================ - - void ElementBndBoxTree::buildChildrenData() - { - for ( int i = 0; i < _elements.size(); ++i ) - { - for (int j = 0; j < 8; j++) - { - if ( !_elements[i]->IsOut( myChildren[j]->getBox() )) - { - _elements[i]->_refCount++; - ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]); - } - } - _elements[i]->_refCount--; - } - _size = _elements.size(); - SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory - - for (int j = 0; j < 8; j++) - { - ElementBndBoxTree* child = static_cast( myChildren[j]); - if ( child->_elements.size() <= MaxNbElemsInLeaf ) - child->myIsLeaf = true; - - if ( child->_elements.capacity() - child->_elements.size() > 1000 ) - SMESHUtils::CompactVector( child->_elements ); - } - } - - //================================================================================ - /*! - * \brief Return elements which can include the point - */ - //================================================================================ - - void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, - TIDSortedElemSet& foundElems) - { - if ( getBox().IsOut( point.XYZ() )) - return; - - if ( isLeaf() ) - { - for ( int i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( point.XYZ() )) - foundElems.insert( _elements[i]->_element ); - } - else - { - for (int i = 0; i < 8; i++) - ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems ); - } - } - - //================================================================================ - /*! - * \brief Return elements which can be intersected by the line - */ - //================================================================================ - - void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, - TIDSortedElemSet& foundElems) - { - if ( getBox().IsOut( line )) - return; - - if ( isLeaf() ) - { - for ( int i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( line )) - foundElems.insert( _elements[i]->_element ); - } - else - { - for (int i = 0; i < 8; i++) - ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems ); - } - } - - //================================================================================ - /*! - * \brief Return elements from leaves intersecting the sphere - */ - //================================================================================ - - void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, - const double radius, - TIDSortedElemSet& foundElems) - { - if ( getBox().IsOut( center, radius )) - return; - - if ( isLeaf() ) - { - for ( int i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( center, radius )) - foundElems.insert( _elements[i]->_element ); - } - else - { - for (int i = 0; i < 8; i++) - ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems ); - } - } - - //================================================================================ - /*! - * \brief Construct the element box - */ - //================================================================================ - - ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance) - { - _element = elem; - _refCount = 1; - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) - Add( SMESH_TNodeXYZ( nIt->next() )); - Enlarge( tolerance ); - } - -} // namespace - -//======================================================================= -/*! - * \brief Implementation of search for the elements by point and - * of classification of point in 2D mesh - */ -//======================================================================= - -struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher -{ - SMESHDS_Mesh* _mesh; - SMDS_ElemIteratorPtr _meshPartIt; - ElementBndBoxTree* _ebbTree; - SMESH_NodeSearcherImpl* _nodeSearcher; - SMDSAbs_ElementType _elementType; - double _tolerance; - bool _outerFacesFound; - set _outerFaces; // empty means "no internal faces at all" - - SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) - : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {} - ~SMESH_ElementSearcherImpl() - { - if ( _ebbTree ) delete _ebbTree; _ebbTree = 0; - if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0; - } - virtual int FindElementsByPoint(const gp_Pnt& point, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElements); - virtual TopAbs_State GetPointState(const gp_Pnt& point); - virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point, - SMDSAbs_ElementType type ); - - void GetElementsNearLine( const gp_Ax1& line, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems); - double getTolerance(); - bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face, - const double tolerance, double & param); - void findOuterBoundary(const SMDS_MeshElement* anyOuterFace); - bool isOuterBoundary(const SMDS_MeshElement* face) const - { - return _outerFaces.empty() || _outerFaces.count(face); - } - struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState()) - { - const SMDS_MeshElement* _face; - gp_Vec _faceNorm; - bool _coincides; //!< the line lays in face plane - TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false) - : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {} - }; - struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary()) - { - SMESH_TLink _link; - TIDSortedElemSet _faces; - TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face) - : _link( n1, n2 ), _faces( &face, &face + 1) {} - }; -}; - -ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i) -{ - return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0) - << ", _coincides="<GetMeshInfo(); - - _tolerance = 0; - if ( _nodeSearcher && meshInfo.NbNodes() > 1 ) - { - double boxSize = _nodeSearcher->getTree()->maxSize(); - _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/; - } - else if ( _ebbTree && meshInfo.NbElements() > 0 ) - { - double boxSize = _ebbTree->maxSize(); - _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/; - } - if ( _tolerance == 0 ) - { - // define tolerance by size of a most complex element - int complexType = SMDSAbs_Volume; - while ( complexType > SMDSAbs_All && - meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 ) - --complexType; - if ( complexType == SMDSAbs_All ) return 0; // empty mesh - double elemSize; - if ( complexType == int( SMDSAbs_Node )) - { - SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator(); - elemSize = 1; - if ( meshInfo.NbNodes() > 2 ) - elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() ); - } - else - { - SMDS_ElemIteratorPtr elemIt = - _mesh->elementsIterator( SMDSAbs_ElementType( complexType )); - const SMDS_MeshElement* elem = elemIt->next(); - SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); - SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() )); - elemSize = 0; - while ( nodeIt->more() ) - { - double dist = n1.Distance( cast2Node( nodeIt->next() )); - elemSize = max( dist, elemSize ); - } - } - _tolerance = 1e-4 * elemSize; - } - } - return _tolerance; -} - -//================================================================================ -/*! - * \brief Find intersection of the line and an edge of face and return parameter on line - */ -//================================================================================ - -bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line, - const SMDS_MeshElement* face, - const double tol, - double & param) -{ - int nbInts = 0; - param = 0; - - GeomAPI_ExtremaCurveCurve anExtCC; - Handle(Geom_Curve) lineCurve = new Geom_Line( line ); - - int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes(); - for ( int i = 0; i < nbNodes && nbInts < 2; ++i ) - { - GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )), - SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); - anExtCC.Init( lineCurve, edge); - if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol) - { - Quantity_Parameter pl, pe; - anExtCC.LowerDistanceParameters( pl, pe ); - param += pl; - if ( ++nbInts == 2 ) - break; - } - } - if ( nbInts > 0 ) param /= nbInts; - return nbInts > 0; -} -//================================================================================ -/*! - * \brief Find all faces belonging to the outer boundary of mesh - */ -//================================================================================ - -void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace) -{ - if ( _outerFacesFound ) return; - - // Collect all outer faces by passing from one outer face to another via their links - // and BTW find out if there are internal faces at all. - - // checked links and links where outer boundary meets internal one - set< SMESH_TLink > visitedLinks, seamLinks; - - // links to treat with already visited faces sharing them - list < TFaceLink > startLinks; - - // load startLinks with the first outerFace - startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace)); - _outerFaces.insert( outerFace ); - - TIDSortedElemSet emptySet; - while ( !startLinks.empty() ) - { - const SMESH_TLink& link = startLinks.front()._link; - TIDSortedElemSet& faces = startLinks.front()._faces; - - outerFace = *faces.begin(); - // find other faces sharing the link - const SMDS_MeshElement* f; - while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces ))) - faces.insert( f ); - - // select another outer face among the found - const SMDS_MeshElement* outerFace2 = 0; - if ( faces.size() == 2 ) - { - outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin()); - } - else if ( faces.size() > 2 ) - { - seamLinks.insert( link ); - - // link direction within the outerFace - gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()), - SMESH_TNodeXYZ( link.node2())); - int i1 = outerFace->GetNodeIndex( link.node1() ); - int i2 = outerFace->GetNodeIndex( link.node2() ); - bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 ); - if ( rev ) n1n2.Reverse(); - // outerFace normal - gp_XYZ ofNorm, fNorm; - if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false )) - { - // direction from the link inside outerFace - gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2; - // sort all other faces by angle with the dirInOF - map< double, const SMDS_MeshElement* > angle2Face; - set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin(); - for ( ; face != faces.end(); ++face ) - { - if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false )) - continue; - gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2; - double angle = dirInOF.AngleWithRef( dirInF, n1n2 ); - if ( angle < 0 ) angle += 2. * M_PI; - angle2Face.insert( make_pair( angle, *face )); - } - if ( !angle2Face.empty() ) - outerFace2 = angle2Face.begin()->second; - } - } - // store the found outer face and add its links to continue seaching from - if ( outerFace2 ) - { - _outerFaces.insert( outerFace ); - int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 ); - for ( int i = 0; i < nbNodes; ++i ) - { - SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes)); - if ( visitedLinks.insert( link2 ).second ) - startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 )); - } - } - startLinks.pop_front(); - } - _outerFacesFound = true; - - if ( !seamLinks.empty() ) - { - // There are internal boundaries touching the outher one, - // find all faces of internal boundaries in order to find - // faces of boundaries of holes, if any. - - } - else - { - _outerFaces.clear(); - } -} - -//======================================================================= -/*! - * \brief Find elements of given type where the given point is IN or ON. - * Returns nb of found elements and elements them-selves. - * - * 'ALL' type means elements of any type excluding nodes, balls and 0D elements - */ -//======================================================================= - -int SMESH_ElementSearcherImpl:: -FindElementsByPoint(const gp_Pnt& point, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElements) -{ - foundElements.clear(); - - double tolerance = getTolerance(); - - // ================================================================================= - if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball) - { - if ( !_nodeSearcher ) - _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh ); - - const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point ); - if ( !closeNode ) return foundElements.size(); - - if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance ) - return foundElements.size(); // to far from any node - - if ( type == SMDSAbs_Node ) - { - foundElements.push_back( closeNode ); - } - else - { - SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type ); - while ( elemIt->more() ) - foundElements.push_back( elemIt->next() ); - } - } - // ================================================================================= - else // elements more complex than 0D - { - if ( !_ebbTree || _elementType != type ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance ); - } - TIDSortedElemSet suspectElems; - _ebbTree->getElementsNearPoint( point, suspectElems ); - TIDSortedElemSet::iterator elem = suspectElems.begin(); - for ( ; elem != suspectElems.end(); ++elem ) - if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance )) - foundElements.push_back( *elem ); - } - return foundElements.size(); -} - -//======================================================================= -/*! - * \brief Find an element of given type most close to the given point - * - * WARNING: Only face search is implemeneted so far - */ -//======================================================================= - -const SMDS_MeshElement* -SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, - SMDSAbs_ElementType type ) -{ - const SMDS_MeshElement* closestElem = 0; - - if ( type == SMDSAbs_Face ) - { - if ( !_ebbTree || _elementType != type ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); - } - TIDSortedElemSet suspectElems; - _ebbTree->getElementsNearPoint( point, suspectElems ); - - if ( suspectElems.empty() && _ebbTree->maxSize() > 0 ) - { - gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox().CornerMin() + - _ebbTree->getBox().CornerMax() ); - double radius; - if ( _ebbTree->getBox().IsOut( point.XYZ() )) - radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize(); - else - radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2; - while ( suspectElems.empty() ) - { - _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); - radius *= 1.1; - } - } - double minDist = std::numeric_limits::max(); - multimap< double, const SMDS_MeshElement* > dist2face; - TIDSortedElemSet::iterator elem = suspectElems.begin(); - for ( ; elem != suspectElems.end(); ++elem ) - { - double dist = SMESH_MeshEditor::GetDistance( dynamic_cast(*elem), - point ); - if ( dist < minDist + 1e-10) - { - minDist = dist; - dist2face.insert( dist2face.begin(), make_pair( dist, *elem )); - } - } - if ( !dist2face.empty() ) - { - multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin(); - closestElem = d2f->second; - // if there are several elements at the same distance, select one - // with GC closest to the point - typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; - double minDistToGC = 0; - for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f ) - { - if ( minDistToGC == 0 ) - { - gp_XYZ gc(0,0,0); - gc = accumulate( TXyzIterator(closestElem->nodesIterator()), - TXyzIterator(), gc ) / closestElem->NbNodes(); - minDistToGC = point.SquareDistance( gc ); - } - gp_XYZ gc(0,0,0); - gc = accumulate( TXyzIterator( d2f->second->nodesIterator()), - TXyzIterator(), gc ) / d2f->second->NbNodes(); - double d = point.SquareDistance( gc ); - if ( d < minDistToGC ) - { - minDistToGC = d; - closestElem = d2f->second; - } - } - // cout << "FindClosestTo( " <GetID() << " DIST " << minDist << endl; - } - } - else - { - // NOT IMPLEMENTED SO FAR - } - return closestElem; -} - - -//================================================================================ -/*! - * \brief Classify the given point in the closed 2D mesh - */ -//================================================================================ - -TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) -{ - double tolerance = getTolerance(); - if ( !_ebbTree || _elementType != SMDSAbs_Face ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt ); - } - // Algo: analyse transition of a line starting at the point through mesh boundary; - // try three lines parallel to axis of the coordinate system and perform rough - // analysis. If solution is not clear perform thorough analysis. - - const int nbAxes = 3; - gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() }; - map< double, TInters > paramOnLine2TInters[ nbAxes ]; - list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line - multimap< int, int > nbInt2Axis; // to find the simplest case - for ( int axis = 0; axis < nbAxes; ++axis ) - { - gp_Ax1 lineAxis( point, axisDir[axis]); - gp_Lin line ( lineAxis ); - - TIDSortedElemSet suspectFaces; // faces possibly intersecting the line - _ebbTree->getElementsNearLine( lineAxis, suspectFaces ); - - // Intersect faces with the line - - map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; - TIDSortedElemSet::iterator face = suspectFaces.begin(); - for ( ; face != suspectFaces.end(); ++face ) - { - // get face plane - gp_XYZ fNorm; - if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue; - gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm ); - - // perform intersection - IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane )); - if ( !intersection.IsDone() ) - continue; - if ( intersection.IsInQuadric() ) - { - tangentInters[ axis ].push_back( TInters( *face, fNorm, true )); - } - else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 ) - { - gp_Pnt intersectionPoint = intersection.Point(1); - if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance )) - u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); - } - } - // Analyse intersections roughly - - int nbInter = u2inters.size(); - if ( nbInter == 0 ) - return TopAbs_OUT; - - double f = u2inters.begin()->first, l = u2inters.rbegin()->first; - if ( nbInter == 1 ) // not closed mesh - return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; - - if ( fabs( f ) < tolerance || fabs( l ) < tolerance ) - return TopAbs_ON; - - if ( (f<0) == (l<0) ) - return TopAbs_OUT; - - int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0)); - int nbIntAfterPoint = nbInter - nbIntBeforePoint; - if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) - return TopAbs_IN; - - nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis )); - - if ( _outerFacesFound ) break; // pass to thorough analysis - - } // three attempts - loop on CS axes - - // Analyse intersections thoroughly. - // We make two loops maximum, on the first one we only exclude touching intersections, - // on the second, if situation is still unclear, we gather and use information on - // position of faces (internal or outer). If faces position is already gathered, - // we make the second loop right away. - - for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo ) - { - multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin(); - for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis ) - { - int axis = nb_axis->second; - map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; - - gp_Ax1 lineAxis( point, axisDir[axis]); - gp_Lin line ( lineAxis ); - - // add tangent intersections to u2inters - double param; - list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin(); - for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt ) - if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param )) - u2inters.insert(make_pair( param, *tgtInt )); - tangentInters[ axis ].clear(); - - // Count intersections before and after the point excluding touching ones. - // If hasPositionInfo we count intersections of outer boundary only - - int nbIntBeforePoint = 0, nbIntAfterPoint = 0; - double f = numeric_limits::max(), l = -numeric_limits::max(); - map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1; - bool ok = ! u_int1->second._coincides; - while ( ok && u_int1 != u2inters.end() ) - { - double u = u_int1->first; - bool touchingInt = false; - if ( ++u_int2 != u2inters.end() ) - { - // skip intersections at the same point (if the line passes through edge or node) - int nbSamePnt = 0; - while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance ) - { - ++nbSamePnt; - ++u_int2; - } - - // skip tangent intersections - int nbTgt = 0; - const SMDS_MeshElement* prevFace = u_int1->second._face; - while ( ok && u_int2->second._coincides ) - { - if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() ) - ok = false; - else - { - nbTgt++; - u_int2++; - ok = ( u_int2 != u2inters.end() ); - } - } - if ( !ok ) break; - - // skip intersections at the same point after tangent intersections - if ( nbTgt > 0 ) - { - double u2 = u_int2->first; - ++u_int2; - while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance ) - { - ++nbSamePnt; - ++u_int2; - } - } - // decide if we skipped a touching intersection - if ( nbSamePnt + nbTgt > 0 ) - { - double minDot = numeric_limits::max(), maxDot = -numeric_limits::max(); - map< double, TInters >::iterator u_int = u_int1; - for ( ; u_int != u_int2; ++u_int ) - { - if ( u_int->second._coincides ) continue; - double dot = u_int->second._faceNorm * line.Direction(); - if ( dot > maxDot ) maxDot = dot; - if ( dot < minDot ) minDot = dot; - } - touchingInt = ( minDot*maxDot < 0 ); - } - } - if ( !touchingInt ) - { - if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face )) - { - if ( u < 0 ) - ++nbIntBeforePoint; - else - ++nbIntAfterPoint; - } - if ( u < f ) f = u; - if ( u > l ) l = u; - } - - u_int1 = u_int2; // to next intersection - - } // loop on intersections with one line - - if ( ok ) - { - if ( fabs( f ) < tolerance || fabs( l ) < tolerance ) - return TopAbs_ON; - - if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0) - return TopAbs_OUT; - - if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh - return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; - - if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) - return TopAbs_IN; - - if ( (f<0) == (l<0) ) - return TopAbs_OUT; - - if ( hasPositionInfo ) - return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT; - } - } // loop on intersections of the tree lines - thorough analysis - - if ( !hasPositionInfo ) - { - // gather info on faces position - is face in the outer boundary or not - map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ]; - findOuterBoundary( u2inters.begin()->second._face ); - } - - } // two attempts - with and w/o faces position info in the mesh - - return TopAbs_UNKNOWN; -} - -//======================================================================= -/*! - * \brief Return elements possibly intersecting the line - */ -//======================================================================= - -void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems) -{ - if ( !_ebbTree || _elementType != type ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); - } - TIDSortedElemSet suspectFaces; // elements possibly intersecting the line - _ebbTree->getElementsNearLine( line, suspectFaces ); - foundElems.assign( suspectFaces.begin(), suspectFaces.end()); -} - -//======================================================================= -/*! - * \brief Return SMESH_ElementSearcher - */ -//======================================================================= - -SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher() -{ - return new SMESH_ElementSearcherImpl( *GetMeshDS() ); -} - -//======================================================================= -/*! - * \brief Return SMESH_ElementSearcher acting on a sub-set of elements - */ -//======================================================================= - -SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt) -{ - return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt ); -} - -//======================================================================= -/*! - * \brief Return true if the point is IN or ON of the element - */ -//======================================================================= - -bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ) -{ - if ( element->GetType() == SMDSAbs_Volume) - { - return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol ); - } - - // get ordered nodes - - vector< gp_XYZ > xyz; - vector nodeList; - - SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); - if ( element->IsQuadratic() ) { - if (const SMDS_VtkFace* f=dynamic_cast(element)) - nodeIt = f->interlacedNodesElemIterator(); - else if (const SMDS_VtkEdge* e =dynamic_cast(element)) - nodeIt = e->interlacedNodesElemIterator(); - } - while ( nodeIt->more() ) - { - const SMDS_MeshNode* node = cast2Node( nodeIt->next() ); - xyz.push_back( SMESH_TNodeXYZ(node) ); - nodeList.push_back(node); - } - - int i, nbNodes = element->NbNodes(); - - if ( element->GetType() == SMDSAbs_Face ) // -------------------------------------------------- - { - // compute face normal - gp_Vec faceNorm(0,0,0); - xyz.push_back( xyz.front() ); - nodeList.push_back( nodeList.front() ); - for ( i = 0; i < nbNodes; ++i ) - { - gp_Vec edge1( xyz[i+1], xyz[i]); - gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] ); - faceNorm += edge1 ^ edge2; - } - double normSize = faceNorm.Magnitude(); - if ( normSize <= tol ) - { - // degenerated face: point is out if it is out of all face edges - for ( i = 0; i < nbNodes; ++i ) - { - SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] ); - if ( !IsOut( &edge, point, tol )) - return false; - } - return true; - } - faceNorm /= normSize; - - // check if the point lays on face plane - gp_Vec n2p( xyz[0], point ); - if ( fabs( n2p * faceNorm ) > tol ) - return true; // not on face plane - - // check if point is out of face boundary: - // define it by closest transition of a ray point->infinity through face boundary - // on the face plane. - // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool - // to find intersections of the ray with the boundary. - gp_Vec ray = n2p; - gp_Vec plnNorm = ray ^ faceNorm; - normSize = plnNorm.Magnitude(); - if ( normSize <= tol ) return false; // point coincides with the first node - plnNorm /= normSize; - // for each node of the face, compute its signed distance to the plane - vector dist( nbNodes + 1); - for ( i = 0; i < nbNodes; ++i ) - { - gp_Vec n2p( xyz[i], point ); - dist[i] = n2p * plnNorm; - } - dist.back() = dist.front(); - // find the closest intersection - int iClosest = -1; - double rClosest, distClosest = 1e100;; - gp_Pnt pClosest; - for ( i = 0; i < nbNodes; ++i ) - { - double r; - if ( fabs( dist[i]) < tol ) - r = 0.; - else if ( fabs( dist[i+1]) < tol ) - r = 1.; - else if ( dist[i] * dist[i+1] < 0 ) - r = dist[i] / ( dist[i] - dist[i+1] ); - else - continue; // no intersection - gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r; - gp_Vec p2int ( point, pInt); - if ( p2int * ray > -tol ) // right half-space - { - double intDist = p2int.SquareMagnitude(); - if ( intDist < distClosest ) - { - iClosest = i; - rClosest = r; - pClosest = pInt; - distClosest = intDist; - } - } - } - if ( iClosest < 0 ) - return true; // no intesections - out - - // analyse transition - gp_Vec edge( xyz[iClosest], xyz[iClosest+1] ); - gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face - gp_Vec p2int ( point, pClosest ); - bool out = (edgeNorm * p2int) < -tol; - if ( rClosest > 0. && rClosest < 1. ) // not node intersection - return out; - - // ray pass through a face node; analyze transition through an adjacent edge - gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ]; - gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ]; - gp_Vec edgeAdjacent( p1, p2 ); - gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm ); - bool out2 = (edgeNorm2 * p2int) < -tol; - - bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0; - return covexCorner ? (out || out2) : (out && out2); - } - if ( element->GetType() == SMDSAbs_Edge ) // -------------------------------------------------- - { - // point is out of edge if it is NOT ON any straight part of edge - // (we consider quadratic edge as being composed of two straight parts) - for ( i = 1; i < nbNodes; ++i ) - { - gp_Vec edge( xyz[i-1], xyz[i]); - gp_Vec n1p ( xyz[i-1], point); - double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude(); - if ( dist > tol ) - continue; - gp_Vec n2p( xyz[i], point ); - if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol ) - continue; - return false; // point is ON this part - } - return true; - } - // Node or 0D element ------------------------------------------------------------------------- - { - gp_Vec n2p ( xyz[0], point ); - return n2p.Magnitude() <= tol; - } - return true; -} - -//======================================================================= - -namespace -{ - // Position of a point relative to a segment - // . . - // . LEFT . - // . . - // VERTEX 1 o----ON-----> VERTEX 2 - // . . - // . RIGHT . - // . . - enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8, - POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX }; - struct PointPos - { - PositionName _name; - int _index; // index of vertex or segment - - PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {} - bool operator < (const PointPos& other ) const - { - if ( _name == other._name ) - return ( _index < 0 || other._index < 0 ) ? false : _index < other._index; - return _name < other._name; - } - }; - - //================================================================================ - /*! - * \brief Return of a point relative to a segment - * \param point2D - the point to analyze position of - * \param xyVec - end points of segments - * \param index0 - 0-based index of the first point of segment - * \param posToFindOut - flags of positions to detect - * \retval PointPos - point position - */ - //================================================================================ - - PointPos getPointPosition( const gp_XY& point2D, - const gp_XY* segEnds, - const int index0 = 0, - const int posToFindOut = POS_ALL) - { - const gp_XY& p1 = segEnds[ index0 ]; - const gp_XY& p2 = segEnds[ index0+1 ]; - const gp_XY grad = p2 - p1; - - if ( posToFindOut & POS_VERTEX ) - { - // check if the point2D is at "vertex 1" zone - gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(), - p1.Y() + grad.X() ) }; - if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT ) - return PointPos( POS_VERTEX, index0 ); - - // check if the point2D is at "vertex 2" zone - gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(), - p2.Y() + grad.X() ) }; - if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT ) - return PointPos( POS_VERTEX, index0 + 1); - } - double edgeEquation = - ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X(); - return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 ); - } -} - -//======================================================================= -/*! - * \brief Return minimal distance from a point to a face - * - * Currently we ignore non-planarity and 2nd order of face - */ -//======================================================================= - -double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face, - const gp_Pnt& point ) -{ - double badDistance = -1; - if ( !face ) return badDistance; - - // coordinates of nodes (medium nodes, if any, ignored) - typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; - vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); - xyz.resize( face->NbCornerNodes()+1 ); - - // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis, - // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane. - gp_Trsf trsf; - gp_Vec OZ ( xyz[0], xyz[1] ); - gp_Vec OX ( xyz[0], xyz[2] ); - if ( OZ.Magnitude() < std::numeric_limits::min() ) - { - if ( xyz.size() < 4 ) return badDistance; - OZ = gp_Vec ( xyz[0], xyz[2] ); - OX = gp_Vec ( xyz[0], xyz[3] ); - } - gp_Ax3 tgtCS; - try { - tgtCS = gp_Ax3( xyz[0], OZ, OX ); - } - catch ( Standard_Failure ) { - return badDistance; - } - trsf.SetTransformation( tgtCS ); - - // move all the nodes to 2D - vector xy( xyz.size() ); - for ( size_t i = 0;i < xyz.size()-1; ++i ) - { - gp_XYZ p3d = xyz[i]; - trsf.Transforms( p3d ); - xy[i].SetCoord( p3d.X(), p3d.Z() ); - } - xyz.back() = xyz.front(); - xy.back() = xy.front(); - - // // move the point in 2D - gp_XYZ tmpPnt = point.XYZ(); - trsf.Transforms( tmpPnt ); - gp_XY point2D( tmpPnt.X(), tmpPnt.Z() ); - - // loop on segments of the face to analyze point position ralative to the face - set< PointPos > pntPosSet; - for ( size_t i = 1; i < xy.size(); ++i ) - { - PointPos pos = getPointPosition( point2D, &xy[0], i-1 ); - pntPosSet.insert( pos ); - } - - // compute distance - PointPos pos = *pntPosSet.begin(); - // cout << "Face " << face->GetID() << " DIST: "; - switch ( pos._name ) - { - case POS_LEFT: { - // point is most close to a segment - gp_Vec p0p1( point, xyz[ pos._index ] ); - gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector - p1p2.Normalize(); - double projDist = p0p1 * p1p2; // distance projected to the segment - gp_Vec projVec = p1p2 * projDist; - gp_Vec distVec = p0p1 - projVec; - // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID() - // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl; - return distVec.Magnitude(); - } - case POS_RIGHT: { - // point is inside the face - double distToFacePlane = tmpPnt.Y(); - // cout << distToFacePlane << ", INSIDE " << endl; - return Abs( distToFacePlane ); - } - case POS_VERTEX: { - // point is most close to a node - gp_Vec distVec( point, xyz[ pos._index ]); - // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl; - return distVec.Magnitude(); - } - } - return badDistance; -} - -//======================================================================= -//function : SimplifyFace -//purpose : -//======================================================================= -int SMESH_MeshEditor::SimplifyFace (const vector faceNodes, - vector& poly_nodes, - vector& quantities) const -{ - int nbNodes = faceNodes.size(); - - if (nbNodes < 3) - return 0; + if (nbNodes < 3) + return 0; set nodeSet; @@ -7488,20 +7333,26 @@ 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; - //MESSAGE("node to keep " << nToKeep->GetID()); - for ( ++nIt; nIt != nodes.end(); nIt++ ) { + for ( ++nIt; nIt != nodes.end(); nIt++ ) + { const SMDS_MeshNode* nToRemove = *nIt; - nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep )); - if ( nToRemove != nToKeep ) { - //MESSAGE(" node to remove " << nToRemove->GetID()); + nodeNodeMap.insert( make_pair( nToRemove, nToKeep )); + if ( nToRemove != nToKeep ) + { rmNodeIds.push_back( nToRemove->GetID() ); AddToSameGroups( nToKeep, nToRemove, aMesh ); + // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing + // after MergeNodes() w/o creating node in place of merged ones. + const SMDS_PositionPtr& pos = nToRemove->GetPosition(); + if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() )) + sm->SetIsAlwaysComputed( true ); } - SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); while ( invElemIt->more() ) { const SMDS_MeshElement* elem = invElemIt->next(); @@ -7511,29 +7362,34 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } // Change element nodes or remove an element + set nodeSet; + vector< const SMDS_MeshNode*> curNodes, uniqueNodes; + vector iRepl; + ElemFeatures elemType; + set::iterator eIt = elems.begin(); - for ( ; eIt != elems.end(); eIt++ ) { + 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 nodeSet; - vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes ); + nodeSet.clear(); + curNodes.resize( nbNodes ); + uniqueNodes.resize( nbNodes ); + iRepl.resize( nbNodes ); int iUnique = 0, iCur = 0, nbRepl = 0; - vector iRepl( nbNodes ); // get new seq of nodes SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* n = - static_cast( itN->next() ); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); if ( nnIt != nodeNodeMap.end() ) { // n sticks n = (*nnIt).second; - // BUG 0020185: begin - { + { ////////// BUG 0020185: begin bool stopRecur = false; set nodesRecur; nodesRecur.insert(n); @@ -7549,8 +7405,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) else stopRecur = true; } - } - // BUG 0020185: end + } ////////// BUG 0020185: end } curNodes[ iCur ] = n; bool isUnique = nodeSet.insert( n ).second; @@ -7565,56 +7420,54 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) 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 face_nodes (nbNodes); - int inode = 0; - for (; inode < nbNodes; inode++) { - face_nodes[inode] = curNodes[inode]; - } + if ( nbNodes != nbUniqueNodes ) // some nodes stick + { + if (elem->IsPoly()) // Polygons and Polyhedral volumes + { + if (elem->GetType() == SMDSAbs_Face) // Polygon + { + elemType.Init( elem ); + const bool isQuad = elemType.myIsQuad; + if ( isQuad ) + SMDS_MeshCell::applyInterlace // interlace medium and corner nodes + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes ); + // a polygon can divide into several elements vector polygons_nodes; vector 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 poly_nodes (nbNodes); - for (int ii = 0; ii < nbNodes; ii++, inode++) { - poly_nodes[ii] = polygons_nodes[inode]; + int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities ); + if (nbNew > 0) + { + vector face_nodes; + int inode = 0; + for (int iface = 0; iface < nbNew; iface++) + { + int nbNewNodes = quantities[iface]; + face_nodes.assign( polygons_nodes.begin() + inode, + polygons_nodes.begin() + inode + nbNewNodes ); + inode += nbNewNodes; + if ( isQuad ) // check if a result elem is a valid quadratic polygon + { + bool isValid = ( nbNewNodes % 2 == 0 ); + for ( int i = 0; i < nbNewNodes && isValid; ++i ) + isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 )); + elemType.SetQuad( isValid ); + if ( isValid ) // put medium nodes after corners + SMDS_MeshCell::applyInterlaceRev + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, + nbNewNodes ), face_nodes ); } - SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); - myLastCreatedElems.Append(newElem); - if (aShapeId) + SMDS_MeshElement* newElem = AddElement( face_nodes, elemType ); + if ( aShapeId ) aMesh->SetMeshElementOnShape(newElem, aShapeId); } - - MESSAGE("ChangeElementNodes MergeNodes Polygon"); - //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]); - vector polynodes(polygons_nodes.begin()+inode,polygons_nodes.end()); - int quid =0; - if (nbNew > 0) quid = nbNew - 1; - vector 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()); } + rmElemIds.push_back(elem->GetID()); - } - else if (elem->GetType() == SMDSAbs_Volume) { - // Polyhedral volume + } // Polygon + + else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume + { if (nbUniqueNodes < 4) { rmElemIds.push_back(elem->GetID()); } @@ -7647,18 +7500,17 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) 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()); - } + + if (quantities.size() > 3) + { + //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); + const SMDS_MeshElement* 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()); @@ -8057,51 +7909,19 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } // 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( 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 // 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); + if ( isOk ) // the non-poly elem remains valid after sticking nodes + { + elemType.Init( elem ).SetID( elem->GetID() ); - SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; + SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; + aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); - 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 ); - } + uniqueNodes.resize(nbUniqueNodes); + SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType ); + if ( sm && newElem ) + sm->AddElement( newElem ); + if ( elem != newElem ) + ReplaceElemInGroups( elem, newElem, aMesh ); } else { // Remove invalid regular element or invalid polygon @@ -8115,6 +7935,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) Remove( rmElemIds, false ); Remove( rmNodeIds, true ); + return; } @@ -8150,56 +7971,54 @@ private: //purpose : Return list of group of elements built on the same nodes. // Search among theElements or in the whole mesh if theElements is empty //======================================================================= -void SMESH_MeshEditor::FindEqualElements(set & theElements, - TListOfListOfElementsID & theGroupsOfElementsID) + +void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements, + TListOfListOfElementsID & theGroupsOfElementsID) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - typedef set TElemsSet; typedef map< SortableElement, int > TMapOfNodeSet; typedef list TGroupOfElems; - TElemsSet elems; if ( theElements.empty() ) { // get all elements in the mesh SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator(); while ( eIt->more() ) - elems.insert( elems.end(), eIt->next()); + theElements.insert( theElements.end(), eIt->next() ); } - else - elems = theElements; vector< TGroupOfElems > arrayOfGroups; TGroupOfElems groupOfElems; TMapOfNodeSet mapOfNodeSet; - TElemsSet::iterator elemIt = elems.begin(); - for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) { + TIDSortedElemSet::iterator elemIt = theElements.begin(); + for ( int i = 0; elemIt != theElements.end(); ++elemIt ) + { 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) ) { + if ( !pp.second ) { // one more coincident elem TMapOfNodeSet::iterator& itSE = pp.first; - ind = (*itSE).second; - arrayOfGroups[ind].push_back(curElem->GetID()); + int ind = (*itSE).second; + arrayOfGroups[ind].push_back( curElem->GetID() ); } else { - groupOfElems.clear(); - groupOfElems.push_back(curElem->GetID()); - arrayOfGroups.push_back(groupOfElems); + arrayOfGroups.push_back( groupOfElems ); + arrayOfGroups.back().push_back( curElem->GetID() ); i++; } } + groupOfElems.clear(); vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin(); - for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) { - groupOfElems = *groupIt; - if ( groupOfElems.size() > 1 ) { - groupOfElems.sort(); - theGroupsOfElementsID.push_back(groupOfElems); + for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) + { + if ( groupIt->size() > 1 ) { + //groupOfElems.sort(); -- theElements is sorted already + theGroupsOfElementsID.push_back( groupOfElems ); + theGroupsOfElementsID.back().splice( theGroupsOfElementsID.back().end(), *groupIt ); } } } @@ -8248,82 +8067,13 @@ void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElemen void SMESH_MeshEditor::MergeEqualElements() { - set aMeshElements; /* empty input - - to merge equal elements in the whole mesh */ + TIDSortedElemSet aMeshElements; /* empty input == + to merge equal elements in the whole mesh */ TListOfListOfElementsID aGroupsOfElementsID; FindEqualElements(aMeshElements, aGroupsOfElementsID); MergeElements(aGroupsOfElementsID); } -//======================================================================= -//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(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 : @@ -8336,7 +8086,7 @@ static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1, TIDSortedElemSet elemSet, avoidSet; if ( elem ) avoidSet.insert ( elem ); - return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet ); + return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ); } //======================================================================= @@ -8452,7 +8202,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirst cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ]; cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ]; // find one more free border - if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) { + if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) { cNL->clear(); cFL->clear(); } @@ -9415,7 +9165,7 @@ namespace //======================================================================= /*! - * \brief Convert elements contained in a submesh to quadratic + * \brief Convert elements contained in a sub-mesh to quadratic * \return int - nb of checked elements */ //======================================================================= @@ -9434,14 +9184,49 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, { nbElem++; const SMDS_MeshElement* elem = ElemItr->next(); - if( !elem || elem->IsQuadratic() ) continue; + if( !elem ) continue; + // analyse a necessity of conversion + const SMDSAbs_ElementType aType = elem->GetType(); + if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume ) + continue; + const SMDSAbs_EntityType aGeomType = elem->GetEntityType(); + bool hasCentralNodes = false; + if ( elem->IsQuadratic() ) + { + bool alreadyOK; + switch ( aGeomType ) { + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Hexa: + alreadyOK = !theHelper.GetIsBiQuadratic(); break; + + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + case SMDSEntity_TriQuad_Hexa: + alreadyOK = theHelper.GetIsBiQuadratic(); + hasCentralNodes = true; + break; + default: + alreadyOK = true; + } + // take into account already present modium nodes + switch ( aType ) { + case SMDSAbs_Volume: + theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break; + case SMDSAbs_Face: + theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break; + case SMDSAbs_Edge: + theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break; + default:; + } + if ( alreadyOK ) + continue; + } // get elem data needed to re-create it // - const int id = elem->GetID(); - const int nbNodes = elem->NbNodes(); - const SMDSAbs_ElementType aType = elem->GetType(); - const SMDSAbs_EntityType aGeomType = elem->GetEntityType(); + const int id = elem->GetID(); + const int nbNodes = elem->NbCornerNodes(); nodes.assign(elem->begin_nodes(), elem->end_nodes()); if ( aGeomType == SMDSEntity_Polyhedra ) nbNodeInFaces = static_cast( elem )->GetQuantities(); @@ -9451,6 +9236,12 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, // remove a linear element GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); + // remove central nodes of biquadratic elements (biquad->quad convertion) + if ( hasCentralNodes ) + for ( size_t i = nbNodes * 2; i < nodes.size(); ++i ) + if ( nodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true ); + const SMDS_MeshElement* NewElem = 0; switch( aType ) @@ -9472,7 +9263,6 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, break; default: NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d); - continue; } break; } @@ -9490,6 +9280,8 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d); break; case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); break; @@ -9503,24 +9295,28 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, continue; } ReplaceElemInGroups( elem, NewElem, GetMeshDS()); - if( NewElem ) + if( NewElem && NewElem->getshapeId() < 1 ) theSm->AddElement( NewElem ); } return nbElem; } - //======================================================================= //function : ConvertToQuadratic //purpose : //======================================================================= -void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) +void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad) { SMESHDS_Mesh* meshDS = GetMeshDS(); SMESH_MesherHelper aHelper(*myMesh); + aHelper.SetIsQuadratic( true ); + aHelper.SetIsBiQuadratic( theToBiQuad ); + aHelper.SetElementsOnShape(true); + aHelper.ToFixNodeParameters( true ); + // convert elements assigned to sub-meshes int nbCheckedElems = 0; if ( myMesh->HasShapeToMesh() ) { @@ -9536,18 +9332,22 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) } } } + + // convert elements NOT assigned to sub-meshes int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes(); - if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes + if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes { + aHelper.SetElementsOnShape(false); SMESHDS_SubMesh *smDS = 0; + + // convert edges SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator(); - while(aEdgeItr->more()) + while( aEdgeItr->more() ) { const SMDS_MeshEdge* edge = aEdgeItr->next(); - if(edge && !edge->IsQuadratic()) + if ( !edge->IsQuadratic() ) { - int id = edge->GetID(); - //MESSAGE("edge->GetID() " << id); + int id = edge->GetID(); const SMDS_MeshNode* n1 = edge->GetNode(0); const SMDS_MeshNode* n2 = edge->GetNode(1); @@ -9556,15 +9356,39 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d); ReplaceElemInGroups( edge, NewEdge, GetMeshDS()); } + else + { + aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge )); + } } + + // convert faces SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator(); - while(aFaceItr->more()) + while( aFaceItr->more() ) { const SMDS_MeshFace* face = aFaceItr->next(); - if(!face || face->IsQuadratic() ) continue; + if ( !face ) continue; + + const SMDSAbs_EntityType type = face->GetEntityType(); + bool alreadyOK; + switch( type ) + { + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + alreadyOK = !theToBiQuad; + aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face )); + break; + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + alreadyOK = theToBiQuad; + aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face )); + break; + default: alreadyOK = false; + } + if ( alreadyOK ) + continue; const int id = face->GetID(); - const SMDSAbs_EntityType type = face->GetEntityType(); vector nodes ( face->begin_nodes(), face->end_nodes()); meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false); @@ -9573,25 +9397,52 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) switch( type ) { case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); + if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node + GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true ); break; + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_BiQuad_Quadrangle: NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node + GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true ); break; - default: + + default:; NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d); } ReplaceElemInGroups( face, NewFace, GetMeshDS()); } + + // convert volumes vector nbNodeInFaces; SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator(); while(aVolumeItr->more()) { const SMDS_MeshVolume* volume = aVolumeItr->next(); - if(!volume || volume->IsQuadratic() ) continue; + if ( !volume ) continue; - const int id = volume->GetID(); const SMDSAbs_EntityType type = volume->GetEntityType(); + if ( volume->IsQuadratic() ) + { + bool alreadyOK; + switch ( type ) + { + case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break; + case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break; + default: alreadyOK = true; + } + if ( alreadyOK ) + { + aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume )); + continue; + } + } + const int id = volume->GetID(); vector nodes (volume->begin_nodes(), volume->end_nodes()); if ( type == SMDSEntity_Polyhedra ) nbNodeInFaces = static_cast(volume)->GetQuantities(); @@ -9607,8 +9458,13 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d ); break; case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes + if ( nodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true ); break; case SMDSEntity_Pyramid: NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], @@ -9628,8 +9484,9 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) if ( !theForce3d ) { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion - aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh - aHelper.FixQuadraticElements(); + // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh + // aHelper.FixQuadraticElements(myError); + SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError); } } @@ -9637,18 +9494,19 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) /*! * \brief Makes given elements quadratic * \param theForce3d - if true, the medium nodes will be placed in the middle of link - * \param theElements - elements to make quadratic + * \param theElements - elements to make quadratic */ //================================================================================ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, - TIDSortedElemSet& theElements) + TIDSortedElemSet& theElements, + const bool theToBiQuad) { if ( theElements.empty() ) return; // we believe that all theElements are of the same type const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType(); - + // get all nodes shared by theElements TIDSortedNodeSet allNodes; TIDSortedElemSet::iterator eIt = theElements.begin(); @@ -9666,25 +9524,36 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(); while ( invIt->more() ) { - const SMDS_MeshElement* e = invIt->next(); + const SMDS_MeshElement* e = invIt->next(); + const SMDSAbs_ElementType type = e->GetType(); if ( e->IsQuadratic() ) { - quadAdjacentElems[ e->GetType() ].insert( e ); - continue; - } - if ( e->GetType() >= elemType ) - { - continue; // same type of more complex linear element + quadAdjacentElems[ type ].insert( e ); + + bool alreadyOK; + switch ( e->GetEntityType() ) { + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break; + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break; + default: alreadyOK = true; + } + if ( alreadyOK ) + continue; } + if ( type >= elemType ) + continue; // same type or more complex linear element - if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second ) + if ( !checkedAdjacentElems[ type ].insert( e ).second ) continue; // e is already checked // check nodes bool allIn = true; - SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + SMDS_NodeIteratorPtr nodeIt = e->nodeIterator(); while ( nodeIt->more() && allIn ) - allIn = allNodes.count( cast2Node( nodeIt->next() )); + allIn = allNodes.count( nodeIt->next() ); if ( allIn ) theElements.insert(e ); } @@ -9692,6 +9561,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, SMESH_MesherHelper helper(*myMesh); helper.SetIsQuadratic( true ); + helper.SetIsBiQuadratic( theToBiQuad ); // add links of quadratic adjacent elements to the helper @@ -9714,26 +9584,51 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) ); } - // make quadratic elements instead of linear ones + // make quadratic (or bi-tri-quadratic) elements instead of linear ones - SMESHDS_Mesh* meshDS = GetMeshDS(); + SMESHDS_Mesh* meshDS = GetMeshDS(); SMESHDS_SubMesh* smDS = 0; for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt ) { const SMDS_MeshElement* elem = *eIt; - if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() ) - continue; - const int id = elem->GetID(); + bool alreadyOK; + int nbCentralNodes = 0; + switch ( elem->GetEntityType() ) { + // linear convertible + case SMDSEntity_Edge: + case SMDSEntity_Triangle: + case SMDSEntity_Quadrangle: + case SMDSEntity_Tetra: + case SMDSEntity_Pyramid: + case SMDSEntity_Hexa: + case SMDSEntity_Penta: alreadyOK = false; nbCentralNodes = 0; break; + // quadratic that can become bi-quadratic + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Hexa: alreadyOK =!theToBiQuad; nbCentralNodes = 0; break; + // bi-quadratic + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break; + case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; nbCentralNodes = 7; break; + // the rest + default: alreadyOK = true; + } + if ( alreadyOK ) continue; + const SMDSAbs_ElementType type = elem->GetType(); + const int id = elem->GetID(); + const int nbNodes = elem->NbCornerNodes(); vector nodes ( elem->begin_nodes(), elem->end_nodes()); + helper.SetSubShape( elem->getshapeId() ); + if ( !smDS || !smDS->Contains( elem )) smDS = meshDS->MeshElements( elem->getshapeId() ); meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false); SMDS_MeshElement * newElem = 0; - switch( nodes.size() ) + switch( nbNodes ) { case 4: // cases for most frequently used element types go first (for optimization) if ( type == SMDSAbs_Volume ) @@ -9764,12 +9659,19 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, ReplaceElemInGroups( elem, newElem, meshDS); if( newElem && smDS ) smDS->AddElement( newElem ); - } - if ( !theForce3d && !getenv("NO_FixQuadraticElements")) + // remove central nodes + for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i ) + if ( nodes[i]->NbInverseElements() == 0 ) + meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true ); + + } // loop on theElements + + if ( !theForce3d ) { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion - helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh - helper.FixQuadraticElements(); + // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh + // helper.FixQuadraticElements( myError ); + SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError); } } @@ -9786,6 +9688,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int nbElem = 0; SMESHDS_Mesh* meshDS = GetMeshDS(); + ElemFeatures elemType; + vector nodes; while( theItr->more() ) { @@ -9793,11 +9697,11 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, nbElem++; if( elem && elem->IsQuadratic()) { - int id = elem->GetID(); - int nbCornerNodes = elem->NbCornerNodes(); - SMDSAbs_ElementType aType = elem->GetType(); + // get elem data + int nbCornerNodes = elem->NbCornerNodes(); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); - vector nodes( elem->begin_nodes(), elem->end_nodes() ); + elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false ); //remove a quadratic element if ( !theSm || !theSm->Contains( elem )) @@ -9805,13 +9709,13 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false ); // remove medium nodes - for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i ) + for ( size_t i = nbCornerNodes; i < nodes.size(); ++i ) if ( nodes[i]->NbInverseElements() == 0 ) meshDS->RemoveFreeNode( nodes[i], theSm ); // add a linear element nodes.resize( nbCornerNodes ); - SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id ); + SMDS_MeshElement * newElem = AddElement( nodes, elemType ); ReplaceElemInGroups(elem, newElem, meshDS); if( theSm && newElem ) theSm->AddElement( newElem ); @@ -9890,8 +9794,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) } // replace given elements by linear ones - typedef SMDS_SetIterator TSetIterator; - SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() )); + SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements ); removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs @@ -9928,7 +9831,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) const SMDS_MeshElement* eComplex = invIt2->next(); if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes)) { - int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size(); + int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size(); if ( nbCommonNodes == e->NbNodes()) { complexFound = true; @@ -9943,8 +9846,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) } } } - elemIt = SMDS_ElemIteratorPtr - (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() )); + elemIt = elemSetIterator( moreElemsToConvert ); removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); } @@ -10293,8 +10195,10 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, //cout << "Side " << iSide << " "; //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl; // find a face by two link nodes - face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet, - &iLinkNode[iSide][0], &iLinkNode[iSide][1] ); + face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2, + *faceSetPtr[ iSide ], avoidSet, + &iLinkNode[iSide][0], + &iLinkNode[iSide][1] ); if ( face[ iSide ]) { //cout << " F " << face[ iSide]->GetID() < nodeIDsToRemove/*, elemIDsToRemove*/; + list< int > nodeIDsToRemove; + vector< const SMDS_MeshNode*> nodes; + ElemFeatures elemType; + // 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 @@ -10415,11 +10323,10 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, const SMDS_MeshElement* e = invElemIt->next(); // get a new suite of nodes: make replacement int nbReplaced = 0, i = 0, nbNodes = e->NbNodes(); - vector< const SMDS_MeshNode*> nodes( nbNodes ); + nodes.resize( nbNodes ); SMDS_ElemIteratorPtr nIt = e->nodesIterator(); while ( nIt->more() ) { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); + const SMDS_MeshNode* n = static_cast( nIt->next() ); nnIt = nReplaceMap.find( n ); if ( nnIt != nReplaceMap.end() ) { nbReplaced++; @@ -10431,21 +10338,17 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // elemIDsToRemove.push_back( e->GetID() ); // else if ( nbReplaced ) + { + elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() ); + aMesh->RemoveElement( e ); + + if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType )) { - SMDSAbs_ElementType etyp = e->GetType(); - SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false); - if (newElem) - { - myLastCreatedElems.Append(newElem); - AddToSameGroups(newElem, e, aMesh); - int aShapeId = e->getshapeId(); - if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } - } - aMesh->RemoveElement(e); + AddToSameGroups( newElem, e, aMesh ); + if ( int aShapeId = e->getshapeId() ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); } + } } } @@ -10627,13 +10530,77 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, return SEW_OK; } +//================================================================================ +/*! + * \brief Create elements equal (on same nodes) to given ones + * \param [in] theElements - a set of elems to duplicate. If it is empty, all + * elements of the uppest dimension are duplicated. + */ +//================================================================================ + +void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements ) +{ + ClearLastCreated(); + SMESHDS_Mesh* mesh = GetMeshDS(); + + // get an element type and an iterator over elements + + SMDSAbs_ElementType type; + SMDS_ElemIteratorPtr elemIt; + vector< const SMDS_MeshElement* > allElems; + if ( theElements.empty() ) + { + if ( mesh->NbNodes() == 0 ) + return; + // get most complex type + SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = { + SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge, + SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node + }; + for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i ) + if ( mesh->GetMeshInfo().NbElements( types[i] )) + { + type = types[i]; + break; + } + // put all elements in the vector + allElems.reserve( mesh->GetMeshInfo().NbElements( type )); + elemIt = mesh->elementsIterator( type ); + while ( elemIt->more() ) + allElems.push_back( elemIt->next()); + elemIt = elemSetIterator( allElems ); + } + else + { + type = (*theElements.begin())->GetType(); + elemIt = elemSetIterator( theElements ); + } + + // duplicate elements + + ElemFeatures elemType; + + vector< const SMDS_MeshNode* > nodes; + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if ( elem->GetType() != type ) + continue; + + elemType.Init( elem, /*basicOnly=*/false ); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); + + AddElement( nodes, elemType ); + } +} + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements \param theElems - the list of elements (edges or faces) to be replicated The nodes for duplication could be found from these elements \param theNodesNot - list of nodes to NOT replicate - \param theAffectedElems - the list of elements (cells and edges) to which the + \param theAffectedElems - the list of elements (cells and edges) to which the replicated nodes should be associated to. \return TRUE if operation has been completed successfully, FALSE otherwise */ @@ -10654,7 +10621,7 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, return false; bool res = false; - std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + TNodeNodeMap anOldNodeToNewNode; // duplicate elements and nodes res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true ); // replce nodes by duplications @@ -10674,16 +10641,18 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, */ //================================================================================ -bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, - const TIDSortedElemSet& theElems, - const TIDSortedElemSet& theNodesNot, - std::map< const SMDS_MeshNode*, - const SMDS_MeshNode* >& theNodeNodeMap, - const bool theIsDoubleElem ) +bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + TNodeNodeMap& theNodeNodeMap, + const bool theIsDoubleElem ) { MESSAGE("doubleNodes"); - // iterate on through element and duplicate them (by nodes duplication) + // iterate through element and duplicate them (by nodes duplication) bool res = false; + std::vector newNodes; + ElemFeatures elemType; + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); for ( ; elemItr != theElems.end(); ++elemItr ) { @@ -10691,22 +10660,25 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, if (!anElem) continue; - bool isDuplicate = false; // duplicate nodes to duplicate element - std::vector newNodes( anElem->NbNodes() ); + bool isDuplicate = false; + newNodes.resize( anElem->NbNodes() ); SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); int ind = 0; - while ( anIter->more() ) - { - - SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); - SMDS_MeshNode* aNewNode = aCurrNode; - if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() ) - aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ]; - else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() ) + while ( anIter->more() ) + { + const SMDS_MeshNode* aCurrNode = static_cast( anIter->next() ); + const SMDS_MeshNode* aNewNode = aCurrNode; + TNodeNodeMap::iterator n2n = theNodeNodeMap.find( aCurrNode ); + if ( n2n != theNodeNodeMap.end() ) + { + aNewNode = n2n->second; + } + else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode )) { // duplicate node aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); + copyPosition( aCurrNode, aNewNode ); theNodeNodeMap[ aCurrNode ] = aNewNode; myLastCreatedNodes.Append( aNewNode ); } @@ -10717,12 +10689,10 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, continue; if ( theIsDoubleElem ) - AddElement(newNodes, anElem->GetType(), anElem->IsPoly()); + AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false )); else - { - MESSAGE("ChangeElementNodes"); - theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() ); - } + theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() ); + res = true; } return res; @@ -10732,14 +10702,14 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements \param theNodes - identifiers of nodes to be doubled - \param theModifiedElems - identifiers of elements to be updated by the new (doubled) - nodes. If list of element identifiers is empty then nodes are doubled but - they not assigned to elements + \param theModifiedElems - identifiers of elements to be updated by the new (doubled) + nodes. If list of element identifiers is empty then nodes are doubled but + they not assigned to elements \return TRUE if operation has been completed successfully, FALSE otherwise */ //================================================================================ -bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, +bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, const std::list< int >& theListOfModifiedElems ) { MESSAGE("DoubleNodes"); @@ -10770,6 +10740,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); if ( aNewNode ) { + copyPosition( aNode, aNewNode ); anOldNodeToNewNode[ aNode ] = aNewNode; myLastCreatedNodes.Append( aNewNode ); } @@ -10780,7 +10751,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, std::map< SMDS_MeshElement*, vector > anElemToNodes; std::list< int >::const_iterator anElemIter; - for ( anElemIter = theListOfModifiedElems.begin(); + for ( anElemIter = theListOfModifiedElems.begin(); anElemIter != theListOfModifiedElems.end(); ++anElemIter ) { int aCurr = *anElemIter; @@ -10792,8 +10763,8 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); int ind = 0; - while ( anIter->more() ) - { + while ( anIter->more() ) + { SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) { @@ -10806,7 +10777,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, anElemToNodes[ anElem ] = aNodeArr; } - // Change nodes of elements + // Change nodes of elements std::map< SMDS_MeshElement*, vector >::iterator anElemToNodesIter = anElemToNodes.begin(); @@ -10871,15 +10842,12 @@ namespace { } void Perform(const gp_Pnt& aPnt, double theTol) { + theTol *= theTol; _state = TopAbs_OUT; _extremum.Perform(aPnt); if ( _extremum.IsDone() ) for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); -#else - _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); -#endif } TopAbs_State State() const { @@ -10888,6 +10856,173 @@ namespace { }; } +//================================================================================ +/*! + \brief Identify the elements that will be affected by node duplication (actual duplication is not performed). + This method is the first step of DoubleNodeElemGroupsInRegion. + \param theElems - list of groups of elements (edges or faces) to be replicated + \param theNodesNot - list of groups of nodes not to replicated + \param theShape - shape to detect affected elements (element which geometric center + located on or inside shape). If the shape is null, detection is done on faces orientations + (select elements with a gravity center on the side given by faces normals). + This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations. + The replicated nodes should be associated to affected elements. + \return groups of affected elements + \sa DoubleNodeElemGroupsInRegion() + */ +//================================================================================ + +bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape, + TIDSortedElemSet& theAffectedElems) +{ + if ( theShape.IsNull() ) + { + std::set alreadyCheckedNodes; + std::set alreadyCheckedElems; + std::set edgesToCheck; + alreadyCheckedNodes.clear(); + alreadyCheckedElems.clear(); + edgesToCheck.clear(); + + // --- iterates on elements to be replicated and get elements by back references from their nodes + + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + int ielem; + for ( ielem=1; elemItr != theElems.end(); ++elemItr ) + { + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + if (!anElem || (anElem->GetType() != SMDSAbs_Face)) + continue; + gp_XYZ normal; + SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true ); + MESSAGE("element " << ielem++ << " normal " << normal.X() << " " << normal.Y() << " " << normal.Z()); + std::set nodesElem; + nodesElem.clear(); + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + nodesElem.insert(aNode); + } + std::set::iterator nodit = nodesElem.begin(); + for (; nodit != nodesElem.end(); nodit++) + { + MESSAGE(" noeud "); + const SMDS_MeshNode* aNode = *nodit; + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end()) + continue; + alreadyCheckedNodes.insert(aNode); + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) + { + MESSAGE(" backelem "); + const SMDS_MeshElement* curElem = backElemItr->next(); + if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end()) + continue; + if (theElems.find(curElem) != theElems.end()) + continue; + alreadyCheckedElems.insert(curElem); + double x=0, y=0, z=0; + int nb = 0; + SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator(); + while ( nodeItr2->more() ) + { + const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next()); + x += anotherNode->X(); + y += anotherNode->Y(); + z += anotherNode->Z(); + nb++; + } + gp_XYZ p; + p.SetCoord( x/nb -aNode->X(), + y/nb -aNode->Y(), + z/nb -aNode->Z() ); + MESSAGE(" check " << p.X() << " " << p.Y() << " " << p.Z()); + if (normal*p > 0) + { + MESSAGE(" --- inserted") + theAffectedElems.insert( curElem ); + } + else if (curElem->GetType() == SMDSAbs_Edge) + edgesToCheck.insert(curElem); + } + } + } + // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes) + std::set::iterator eit = edgesToCheck.begin(); + for( ; eit != edgesToCheck.end(); eit++) + { + bool onside = true; + const SMDS_MeshElement* anEdge = *eit; + SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end()) + { + onside = false; + break; + } + } + if (onside) + { + MESSAGE(" --- edge onside inserted") + theAffectedElems.insert(anEdge); + } + } + } + else + { + const double aTol = Precision::Confusion(); + auto_ptr< BRepClass3d_SolidClassifier> bsc3d; + auto_ptr<_FaceClassifier> aFaceClassifier; + if ( theShape.ShapeType() == TopAbs_SOLID ) + { + bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; + bsc3d->PerformInfinitePoint(aTol); + } + else if (theShape.ShapeType() == TopAbs_FACE ) + { + aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + } + + // iterates on indicated elements and get elements by back references from their nodes + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + int ielem; + for ( ielem = 1; elemItr != theElems.end(); ++elemItr ) + { + MESSAGE("element " << ielem++); + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + if (!anElem) + continue; + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) + { + MESSAGE(" noeud "); + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) + { + MESSAGE(" backelem "); + const SMDS_MeshElement* curElem = backElemItr->next(); + if ( curElem && theElems.find(curElem) == theElems.end() && + ( bsc3d.get() ? + isInside( curElem, *bsc3d, aTol ) : + isInside( curElem, *aFaceClassifier, aTol ))) + theAffectedElems.insert( curElem ); + } + } + } + } + return true; +} + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements @@ -10969,23 +11104,34 @@ double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Vec v2(p0, g2); gp_Vec n1 = vref.Crossed(v1); gp_Vec n2 = vref.Crossed(v2); - return n2.AngleWithRef(n1, vref); + try { + return n2.AngleWithRef(n1, vref); + } + catch ( Standard_Failure ) { + } + return Max( v1.Magnitude(), v2.Magnitude() ); } /*! * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. - * The list of groups must describe a partition of the mesh volumes. - * The nodes of the internal faces at the boundaries of the groups are doubled. - * In option, the internal faces are replaced by flat elements. - * Triangles are transformed in prisms, and quadrangles in hexahedrons. - * The flat elements are stored in groups of volumes. - * @param theElems - list of groups of volumes, where a group of volume is a set of - * SMDS_MeshElements sorted by Id. - * @param createJointElems - if TRUE, create the elements - * @return TRUE if operation has been completed successfully, FALSE otherwise + * The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups. + * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements. + * Triangles are transformed into prisms, and quadrangles into hexahedrons. + * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list: + * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list. + * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created. + * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation). + * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples". + * \param theElems - list of groups of volumes, where a group of volume is a set of + * SMDS_MeshElements sorted by Id. + * \param createJointElems - if TRUE, create the elements + * \param onAllBoundaries - if TRUE, the nodes and elements are also created on + * the boundary between \a theDomains and the rest mesh + * \return TRUE if operation has been completed successfully, FALSE otherwise */ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems, - bool createJointElems) + bool createJointElems, + bool onAllBoundaries) { MESSAGE("----------------------------------------------"); MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries"); @@ -11012,20 +11158,51 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector emptySet; emptyMap.clear(); - for (int idom = 0; idom < theElems.size(); idom++) + MESSAGE(".. Number of domains :"< volume to modify) // with all the faces shared by 2 domains (group of elements) // and corresponding volume of this domain, for each shared face. - // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain. + // a volume has a face shared by 2 domains if it has a neighbor which is not in his domain. - //MESSAGE("Domain " << idom); + MESSAGE("... Neighbors of domain #" << idom); const TIDSortedElemSet& domain = theElems[idom]; TIDSortedElemSet::const_iterator elemItr = domain.begin(); for (; elemItr != domain.end(); ++elemItr) { - SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr; + const SMDS_MeshElement* anElem = *elemItr; if (!anElem) continue; int vtkId = anElem->getVtkId(); @@ -11038,17 +11215,31 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorfromVtkToSmds(neighborsVtkIds[n]); const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); - if (! domain.count(elem)) // neighbor is in another domain : face is shared + if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared { - DownIdType face(downIds[n], downTypes[n]); - if (!faceDomains.count(face)) - faceDomains[face] = emptyMap; // create an empty entry for face - if (!faceDomains[face].count(idom)) + bool ok = false ; + for (int idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list + { + // MESSAGE("Domain " << idombis); + const TIDSortedElemSet& domainbis = theElems[idombis]; + if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept + } + if ( ok || onAllBoundaries ) // the characteristics of the face is stored + { + DownIdType face(downIds[n], downTypes[n]); + if (!faceDomains[face].count(idom)) + { + faceDomains[face][idom] = vtkId; // volume associated to face in this domain + celldom[vtkId] = idom; + //MESSAGE(" cell with a border " << vtkId << " domain " << idom); + } + if ( !ok ) { - faceDomains[face][idom] = vtkId; // volume associated to face in this domain - celldom[vtkId] = idom; - //MESSAGE(" cell with a border " << vtkId << " domain " << idom); + theRestDomElems.insert( elem ); + faceDomains[face][iRestDom] = neighborsVtkIds[n]; + celldom[neighborsVtkIds[n]] = iRestDom; } + } } } } @@ -11061,14 +11252,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector domvol = itface->second; + const std::map& domvol = itface->second; if (!domvol.count(idomain)) continue; DownIdType face = itface->first; @@ -11081,8 +11272,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector cells; - cells.clear(); vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); for (int i=0; i > mutipleNodes; // nodes multi domains with domain order std::map > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains) - for (int idomain = 0; idomain < theElems.size(); idomain++) + MESSAGE(".. Duplication of the nodes"); + for (int idomain = idom0; idomain < nbDomains; idomain++) { itface = faceDomains.begin(); for (; itface != faceDomains.end(); ++itface) { - std::map domvol = itface->second; + const std::map& domvol = itface->second; if (!domvol.count(idomain)) continue; DownIdType face = itface->first; @@ -11134,17 +11322,16 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector oldNodes; oldNodes.clear(); grid->GetNodeIds(oldNodes, face.cellId, face.cellType); - bool isMultipleDetected = false; std::set::iterator itn = oldNodes.begin(); for (; itn != oldNodes.end(); ++itn) { int oldId = *itn; - //MESSAGE(" node " << oldId); - if (!nodeDomains.count(oldId)) - nodeDomains[oldId] = emptyMap; // create an empty entry for node if (nodeDomains[oldId].empty()) - nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain - std::map::iterator itdom = domvol.begin(); + { + nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain + //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain); + } + std::map::const_iterator itdom = domvol.begin(); for (; itdom != domvol.end(); ++itdom) { int idom = itdom->first; @@ -11155,7 +11342,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector orderedDoms; //MESSAGE("multiple node " << oldId); - isMultipleDetected =true; if (mutipleNodes.count(oldId)) orderedDoms = mutipleNodes[oldId]; else @@ -11173,18 +11359,39 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorGetPoint(oldId); SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]); + copyPosition( meshDS->FindNodeVtk( oldId ), newNode ); int newId = newNode->getVtkId(); nodeDomains[oldId][idom] = newId; // cloned node for other domains - //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <= 3) - { - //MESSAGE("confirm multiple node " << oldId); - isMultipleDetected =true; + //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" < domvol = itface->second; + if (!domvol.count(idomain)) + continue; + DownIdType face = itface->first; + //MESSAGE(" --- face " << face.cellId); + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + int nbMultipleNodes = 0; + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (mutipleNodes.count(oldId)) + nbMultipleNodes++; + } + if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains { //MESSAGE("multiple Nodes detected on a shared face"); int downId = itface->first.cellId; @@ -11198,7 +11405,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorgetDownArray(cellType)->getNumberOfDownCells(downId); @@ -11212,9 +11419,12 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector vn0 = mutipleNodes[nodes[0]]; vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; - sort( vn0.begin(), vn0.end() ); - sort( vn1.begin(), vn1.end() ); - if (vn0 == vn1) + vector doms; + for (int i0 = 0; i0 < vn0.size(); i0++) + for (int i1 = 0; i1 < vn1.size(); i1++) + if (vn0[i0] == vn1[i1]) + doms.push_back(vn0[i0]); + if (doms.size() >2) { //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]); double *coords = grid->GetPoint(nodes[0]); @@ -11226,14 +11436,15 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector domvol; // domain --> a volume with the edge map angleDom; // oriented angles between planes defined by edge and volume centers int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]); - for (int id=0; id < vn0.size(); id++) + for (int id=0; id < doms.size(); id++) { - int idom = vn0[id]; + int idom = doms[id]; + const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom]; for (int ivol=0; ivolfromVtkToSmds(vtkVolIds[ivol]); SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId); - if (theElems[idom].count(elem)) + if (domain.count(elem)) { SMDS_VtkVolume* svol = dynamic_cast(elem); domvol[idom] = svol; @@ -11289,8 +11500,17 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector > nodeQuadDomains; std::map mapOfJunctionGroups; + MESSAGE(".. Creation of elements: simple junction"); if (createJointElems) { + int idg; + string joints2DName = "joints2D"; + mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg); + SMESHDS_Group *joints2DGrp = dynamic_cast(mapOfJunctionGroups[joints2DName]->GetGroupDS()); + string joints3DName = "joints3D"; + mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg); + SMESHDS_Group *joints3DGrp = dynamic_cast(mapOfJunctionGroups[joints3DName]->GetGroupDS()); + itface = faceDomains.begin(); for (; itface != faceDomains.end(); ++itface) { @@ -11314,13 +11534,16 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectormyMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg); SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); if (sgrp) sgrp->Add(vol->GetID()); + if (vol->GetType() == SMDSAbs_Volume) + joints3DGrp->Add(vol->GetID()); + else if (vol->GetType() == SMDSAbs_Face) + joints2DGrp->Add(vol->GetID()); } } @@ -11328,6 +11551,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorGetMeshDS()->AddVolumeFromVtkIds(orderedNodes); - stringstream grpname; - grpname << "mj_"; - grpname << 0 << "_" << 0; int idg; - string namegrp = grpname.str(); + string namegrp = "jointsMultiples"; if (!mapOfJunctionGroups.count(namegrp)) mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); @@ -11387,7 +11608,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector >::const_iterator itnod = nodeDomains.begin(); for (; itnod != nodeDomains.end(); ++itnod) @@ -11476,6 +11698,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector::iterator name_group = mapOfJunctionGroups.begin(); + for ( ; name_group != mapOfJunctionGroups.end(); ++name_group ) + { + if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() ) + myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() ); + } + meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory grid->BuildLinks(); @@ -11543,6 +11773,7 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vectorAddNode(node->X(), node->Y(), node->Z()); + copyPosition( node, clone ); clonedNodes[node] = clone; } else @@ -11559,6 +11790,7 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vectorAddNode(node->X(), node->Y(), node->Z()); + copyPosition( node, inter ); intermediateNodes[node] = inter; } else @@ -11645,6 +11877,537 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector& nodesCoords, + std::vector >& listOfListOfNodes) +{ + MESSAGE("--------------------------------"); + MESSAGE("SMESH_MeshEditor::CreateHoleSkin"); + MESSAGE("--------------------------------"); + + // --- zone of volumes to remove is given : + // 1 either by a geom shape (one or more vertices) and a radius, + // 2 either by a group of nodes (representative of the shape)to use with the radius, + // 3 either by a group of nodes where all the elements build on one of this nodes are to remove, + // In the case 2, the group of nodes is an external group of nodes from another mesh, + // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter), + // defined by it's name. + + SMESHDS_GroupBase* groupDS = 0; + SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups(); + while ( groupIt->more() ) + { + groupDS = 0; + SMESH_Group * group = groupIt->next(); + if ( !group ) continue; + groupDS = group->GetGroupDS(); + if ( !groupDS || groupDS->IsEmpty() ) continue; + std::string grpName = group->GetName(); + //MESSAGE("grpName=" << grpName); + if (grpName == groupName) + break; + else + groupDS = 0; + } + + bool isNodeGroup = false; + bool isNodeCoords = false; + if (groupDS) + { + if (groupDS->GetType() != SMDSAbs_Node) + return; + isNodeGroup = true; // a group of nodes exists and it is in this mesh + } + + if (nodesCoords.size() > 0) + isNodeCoords = true; // a list o nodes given by their coordinates + //MESSAGE("---" << isNodeGroup << " " << isNodeCoords); + + // --- define groups to build + + int idg; // --- group of SMDS volumes + string grpvName = groupName; + grpvName += "_vol"; + SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg); + if (!grp) + { + MESSAGE("group not created " << grpvName); + return; + } + SMESHDS_Group *sgrp = dynamic_cast(grp->GetGroupDS()); + + int idgs; // --- group of SMDS faces on the skin + string grpsName = groupName; + grpsName += "_skin"; + SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs); + if (!grps) + { + MESSAGE("group not created " << grpsName); + return; + } + SMESHDS_Group *sgrps = dynamic_cast(grps->GetGroupDS()); + + int idgi; // --- group of SMDS faces internal (several shapes) + string grpiName = groupName; + grpiName += "_internalFaces"; + SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi); + if (!grpi) + { + MESSAGE("group not created " << grpiName); + return; + } + SMESHDS_Group *sgrpi = dynamic_cast(grpi->GetGroupDS()); + + int idgei; // --- group of SMDS faces internal (several shapes) + string grpeiName = groupName; + grpeiName += "_internalEdges"; + SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei); + if (!grpei) + { + MESSAGE("group not created " << grpeiName); + return; + } + SMESHDS_Group *sgrpei = dynamic_cast(grpei->GetGroupDS()); + + // --- build downward connectivity + + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + meshDS->BuildDownWardConnectivity(true); + SMDS_UnstructuredGrid* grid = meshDS->getGrid(); + + // --- set of volumes detected inside + + std::set setOfInsideVol; + std::set setOfVolToCheck; + + std::vector gpnts; + gpnts.clear(); + + if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes + { + MESSAGE("group of nodes provided"); + SMDS_ElemIteratorPtr elemIt = groupDS->GetElements(); + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if (!elem) + continue; + const SMDS_MeshNode* node = dynamic_cast(elem); + if (!node) + continue; + SMDS_MeshElement* vol = 0; + SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume); + while (volItr->more()) + { + vol = (SMDS_MeshElement*)volItr->next(); + setOfInsideVol.insert(vol->getVtkId()); + sgrp->Add(vol->GetID()); + } + } + } + else if (isNodeCoords) + { + MESSAGE("list of nodes coordinates provided"); + int i = 0; + int k = 0; + while (i < nodesCoords.size()-2) + { + double x = nodesCoords[i++]; + double y = nodesCoords[i++]; + double z = nodesCoords[i++]; + gp_Pnt p = gp_Pnt(x, y ,z); + gpnts.push_back(p); + MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z()); + k++; + } + } + else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius + { + MESSAGE("no group of nodes provided, using vertices from geom shape, and radius"); + TopTools_IndexedMapOfShape vertexMap; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap ); + gp_Pnt p = gp_Pnt(0,0,0); + if (vertexMap.Extent() < 1) + return; + + for ( int i = 1; i <= vertexMap.Extent(); ++i ) + { + const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i )); + p = BRep_Tool::Pnt(vertex); + gpnts.push_back(p); + MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z()); + } + } + + if (gpnts.size() > 0) + { + int nodeId = 0; + const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]); + if (startNode) + nodeId = startNode->GetID(); + MESSAGE("nodeId " << nodeId); + + double radius2 = radius*radius; + MESSAGE("radius2 " << radius2); + + // --- volumes on start node + + setOfVolToCheck.clear(); + SMDS_MeshElement* startVol = 0; + SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume); + while (volItr->more()) + { + startVol = (SMDS_MeshElement*)volItr->next(); + setOfVolToCheck.insert(startVol->getVtkId()); + } + if (setOfVolToCheck.empty()) + { + MESSAGE("No volumes found"); + return; + } + + // --- starting with central volumes then their neighbors, check if they are inside + // or outside the domain, until no more new neighbor volume is inside. + // Fill the group of inside volumes + + std::map mapOfNodeDistance2; + mapOfNodeDistance2.clear(); + std::set setOfOutsideVol; + while (!setOfVolToCheck.empty()) + { + std::set::iterator it = setOfVolToCheck.begin(); + int vtkId = *it; + MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + bool volInside = false; + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(vtkId, npts, pts); + for (int i=0; iGetPoint(pts[i]); + gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]); + distance2 = 1.E40; + for (int j=0; jAdd(meshDS->fromVtkToSmds(vtkId)); + break; + } + } + if (volInside) + { + setOfInsideVol.insert(vtkId); + MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n])) + setOfVolToCheck.insert(neighborsVtkIds[n]); + } + else + { + setOfOutsideVol.insert(vtkId); + MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + } + setOfVolToCheck.erase(vtkId); + } + } + + // --- for outside hexahedrons, check if they have more than one neighbor volume inside + // If yes, add the volume to the inside set + + bool addedInside = true; + std::set setOfVolToReCheck; + while (addedInside) + { + MESSAGE(" --------------------------- re check"); + addedInside = false; + std::set::iterator itv = setOfInsideVol.begin(); + for (; itv != setOfInsideVol.end(); ++itv) + { + int vtkId = *itv; + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (!setOfInsideVol.count(neighborsVtkIds[n])) + setOfVolToReCheck.insert(neighborsVtkIds[n]); + } + setOfVolToCheck = setOfVolToReCheck; + setOfVolToReCheck.clear(); + while (!setOfVolToCheck.empty()) + { + std::set::iterator it = setOfVolToCheck.begin(); + int vtkId = *it; + if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON) + { + MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int countInside = 0; + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (setOfInsideVol.count(neighborsVtkIds[n])) + countInside++; + MESSAGE("countInside " << countInside); + if (countInside > 1) + { + MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + setOfInsideVol.insert(vtkId); + sgrp->Add(meshDS->fromVtkToSmds(vtkId)); + addedInside = true; + } + else + setOfVolToReCheck.insert(vtkId); + } + setOfVolToCheck.erase(vtkId); + } + } + + // --- map of Downward faces at the boundary, inside the global volume + // map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin) + // fill group of SMDS faces inside the volume (when several volume shapes) + // fill group of SMDS faces on the skin of the global volume (if skin) + + std::map boundaryFaces; // boundary faces inside the volume --> corresponding cell + std::map skinFaces; // faces on the skin of the global volume --> corresponding cell + std::set::iterator it = setOfInsideVol.begin(); + for (; it != setOfInsideVol.end(); ++it) + { + int vtkId = *it; + //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true); + for (int n = 0; n < nbNeighbors; n++) + { + int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n])); + if (neighborDim == 3) + { + if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary + { + DownIdType face(downIds[n], downTypes[n]); + boundaryFaces[face] = vtkId; + } + // if the face between to volumes is in the mesh, get it (internal face between shapes) + int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]); + if (vtkFaceId >= 0) + { + sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId)); + // find also the smds edges on this face + int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]); + const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]); + const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]); + for (int i = 0; i < nbEdges; i++) + { + int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]); + if (vtkEdgeId >= 0) + sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId)); + } + } + } + else if (neighborDim == 2) // skin of the volume + { + DownIdType face(downIds[n], downTypes[n]); + skinFaces[face] = vtkId; + int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]); + if (vtkFaceId >= 0) + sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId)); + } + } + } + + // --- identify the edges constituting the wire of each subshape on the skin + // define polylines with the nodes of edges, equivalent to wires + // project polylines on subshapes, and partition, to get geom faces + + std::map > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin + std::set emptySet; + emptySet.clear(); + std::set shapeIds; + + SMDS_ElemIteratorPtr itelem = sgrps->GetElements(); + while (itelem->more()) + { + const SMDS_MeshElement *elem = itelem->next(); + int shapeId = elem->getshapeId(); + int vtkId = elem->getVtkId(); + if (!shapeIdToVtkIdSet.count(shapeId)) + { + shapeIdToVtkIdSet[shapeId] = emptySet; + shapeIds.insert(shapeId); + } + shapeIdToVtkIdSet[shapeId].insert(vtkId); + } + + std::map > shapeIdToEdges; // shapeId --> set of downward edges + std::set emptyEdges; + emptyEdges.clear(); + + std::map >::iterator itShape = shapeIdToVtkIdSet.begin(); + for (; itShape != shapeIdToVtkIdSet.end(); ++itShape) + { + int shapeId = itShape->first; + MESSAGE(" --- Shape ID --- "<< shapeId); + shapeIdToEdges[shapeId] = emptyEdges; + + std::vector nodesEdges; + + std::set::iterator its = itShape->second.begin(); + for (; its != itShape->second.end(); ++its) + { + int vtkId = *its; + MESSAGE(" " << vtkId); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + { + if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here + continue; + int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group + { + DownIdType edge(downIds[n], downTypes[n]); + if (!shapeIdToEdges[shapeId].count(edge)) + { + shapeIdToEdges[shapeId].insert(edge); + int vtkNodeId[3]; + int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId); + nodesEdges.push_back(vtkNodeId[0]); + nodesEdges.push_back(vtkNodeId[nbNodes-1]); + MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1); + } + } + } + } + + std::list order; + order.clear(); + if (nodesEdges.size() > 0) + { + order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1; + nodesEdges[0] = -1; + order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[1] = -1; // do not reuse this edge + bool found = true; + while (found) + { + int nodeTofind = order.back(); // try first to push back + int i = 0; + for (i = 0; i use the previous one + if (nodesEdges[i-1] < 0) + found = false; + else + { + order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[i-1] = -1; + } + else // even ==> use the next one + if (nodesEdges[i+1] < 0) + found = false; + else + { + order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[i+1] = -1; + } + } + if (found) + continue; + // try to push front + found = true; + nodeTofind = order.front(); // try to push front + for (i = 0; i use the previous one + if (nodesEdges[i-1] < 0) + found = false; + else + { + order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1); + nodesEdges[i-1] = -1; + } + else // even ==> use the next one + if (nodesEdges[i+1] < 0) + found = false; + else + { + order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1); + nodesEdges[i+1] = -1; + } + } + } + + + std::vector nodes; + nodes.push_back(shapeId); + std::list::iterator itl = order.begin(); + for (; itl != order.end(); itl++) + { + nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1; + MESSAGE(" ordered node " << nodes[nodes.size()-1]); + } + listOfListOfNodes.push_back(nodes); + } + + // partition geom faces with blocFissure + // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose) + // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose) + + return; +} + + //================================================================================ /*! * \brief Generates skin mesh (containing 2D cells) from 3D mesh @@ -11659,7 +12422,8 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() SMESHDS_Mesh* aMesh = GetMeshDS(); if (!aMesh) return false; - //bool res = false; + + ElemFeatures faceType( SMDSAbs_Face ); int nbFree = 0, nbExisted = 0, nbCreated = 0; SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator(); while(vIt->more()) @@ -11667,8 +12431,8 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() const SMDS_MeshVolume* volume = vIt->next(); SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false ); vTool.SetExternalNormal(); - //const bool isPoly = volume->IsPoly(); const int iQuad = volume->IsQuadratic(); + faceType.SetQuad( iQuad ); for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) { if (!vTool.IsFreeFace(iface)) @@ -11680,22 +12444,27 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() int inode = 0; for ( ; inode < nbFaceNodes; inode += iQuad+1) nodes.push_back(faceNodes[inode]); - if (iQuad) { // add medium nodes + + if (iQuad) // add medium nodes + { for ( inode = 1; inode < nbFaceNodes; inode += 2) nodes.push_back(faceNodes[inode]); if ( nbFaceNodes == 9 ) // bi-quadratic quad nodes.push_back(faceNodes[8]); } // add new face based on volume nodes - if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) { - nbExisted++; - continue; // face already exsist + if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) + { + nbExisted++; // face already exsist + } + else + { + AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 )); + nbCreated++; } - AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 )); - nbCreated++; } } - return ( nbFree==(nbExisted+nbCreated) ); + return ( nbFree == ( nbExisted + nbCreated )); } namespace @@ -11757,27 +12526,28 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, SMDS_VolumeTool vTool; TIDSortedElemSet avoidSet; const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet; - int inode; + size_t inode; typedef vector TConnectivity; + TConnectivity tgtNodes; + ElemFeatures elemKind( missType ), elemToCopy; SMDS_ElemIteratorPtr eIt; - if (elements.empty()) - eIt = aMesh->elementsIterator(elemType); - else - eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + if (elements.empty()) eIt = aMesh->elementsIterator(elemType); + else eIt = elemSetIterator( elements ); while (eIt->more()) { const SMDS_MeshElement* elem = eIt->next(); - const int iQuad = elem->IsQuadratic(); + const int iQuad = elem->IsQuadratic(); + elemKind.SetQuad( iQuad ); // ------------------------------------------------------------------------------------ // 1. For an elem, get present bnd elements and connectivities of missing bnd elements // ------------------------------------------------------------------------------------ vector presentBndElems; vector missingBndElems; - TConnectivity nodes; + TConnectivity nodes, elemNodes; if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume -------------- { vTool.SetExternalNormal(); @@ -11787,17 +12557,17 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, if ( !vTool.IsFreeFace(iface, &otherVol) && ( !aroundElements || elements.count( otherVol ))) continue; - const int nbFaceNodes = vTool.NbFaceNodes(iface); const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface); + const size_t nbFaceNodes = vTool.NbFaceNodes (iface); if ( missType == SMDSAbs_Edge ) // boundary edges { nodes.resize( 2+iQuad ); for ( int i = 0; i < nbFaceNodes; i += 1+iQuad) { for ( int j = 0; j < nodes.size(); ++j ) - nodes[j] =nn[i+j]; + nodes[j] = nn[ i+j ]; if ( const SMDS_MeshElement* edge = - aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false)) + aMesh->FindElement( nodes, SMDSAbs_Edge, /*noMedium=*/false )) presentBndElems.push_back( edge ); else missingBndElems.push_back( nodes ); @@ -11807,10 +12577,10 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, { nodes.clear(); for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad) - nodes.push_back( nn[inode] ); - if (iQuad) // add medium nodes + nodes.push_back( nn[inode] ); // add corner nodes + if (iQuad) for ( inode = 1; inode < nbFaceNodes; inode += 2) - nodes.push_back( nn[inode] ); + nodes.push_back( nn[inode] ); // add medium nodes int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27 if ( iCenter > 0 ) nodes.push_back( vTool.GetNodes()[ iCenter ] ); @@ -11838,22 +12608,24 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, } } } - else // elem is a face ------------------------------------------ + else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------ { avoidSet.clear(), avoidSet.insert( elem ); - int nbNodes = elem->NbCornerNodes(); - nodes.resize( 2 /*+ iQuad*/); - for ( int i = 0; i < nbNodes; i++ ) + elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ), + SMDS_MeshElement::iterator() ); + elemNodes.push_back( elemNodes[0] ); + nodes.resize( 2 + iQuad ); + const int nbLinks = elem->NbCornerNodes(); + for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad ) { - nodes[0] = elem->GetNode(i); - nodes[1] = elem->GetNode((i+1)%nbNodes); - if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet)) + nodes[0] = elemNodes[iN]; + nodes[1] = elemNodes[iN+1+iQuad]; + if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet)) continue; // not free link - //if ( iQuad ) - //nodes[2] = elem->GetNode( i + nbNodes ); + if ( iQuad ) nodes[2] = elemNodes[iN+1]; if ( const SMDS_MeshElement* edge = - aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true)) + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false)) presentBndElems.push_back( edge ); else missingBndElems.push_back( nodes ); @@ -11866,17 +12638,17 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, if ( targetMesh != myMesh ) // instead of making a map of nodes in this mesh and targetMesh, // we create nodes with same IDs. - for ( int i = 0; i < missingBndElems.size(); ++i ) + for ( size_t i = 0; i < missingBndElems.size(); ++i ) { TConnectivity& srcNodes = missingBndElems[i]; - TConnectivity nodes( srcNodes.size() ); - for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); - if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes, + tgtNodes.resize( srcNodes.size() ); + for ( inode = 0; inode < srcNodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); + if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( tgtNodes, missType, /*noMedium=*/false)) continue; - tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4); + tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 )); ++nbAddedBnd; } else @@ -11887,16 +12659,16 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, missType, /*noMedium=*/false)) continue; - SMDS_MeshElement* elem = - tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4); - ++nbAddedBnd; + SMDS_MeshElement* newElem = + tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 )); + nbAddedBnd += bool( newElem ); // try to set a new element to a shape if ( myMesh->HasShapeToMesh() ) { bool ok = true; set< pair > mediumShapes; - const int nbN = nodes.size() / (iQuad+1 ); + const size_t nbN = nodes.size() / (iQuad+1 ); for ( inode = 0; inode < nbN && ok; ++inode ) { pair i_stype = @@ -11916,7 +12688,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, } } if ( ok && mediumShapes.begin()->first == missShapeType ) - aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second ); + aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second ); } } @@ -11927,17 +12699,17 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, for ( int i = 0 ; i < presentBndElems.size(); ++i ) { const SMDS_MeshElement* e = presentBndElems[i]; - TConnectivity nodes( e->NbNodes() ); + tgtNodes.resize( e->NbNodes() ); for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); - presentEditor->AddElement(nodes, e->GetType(), e->IsPoly()); + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); + presentEditor->AddElement( tgtNodes, elemToCopy.Init( e )); } else // store present elements to add them to a group for ( int i = 0 ; i < presentBndElems.size(); ++i ) { - presentEditor->myLastCreatedElems.Append(presentBndElems[i]); + presentEditor->myLastCreatedElems.Append( presentBndElems[i] ); } - + } // loop on given elements // --------------------------------------------- @@ -11957,20 +12729,60 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, // ----------------------- if ( toCopyElements && targetMesh != myMesh ) { - if (elements.empty()) - eIt = aMesh->elementsIterator(elemType); - else - eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + if (elements.empty()) eIt = aMesh->elementsIterator(elemType); + else eIt = elemSetIterator( elements ); while (eIt->more()) { const SMDS_MeshElement* elem = eIt->next(); - TConnectivity nodes( elem->NbNodes() ); - for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); - tgtEditor.AddElement(nodes, elemType, elem->IsPoly()); + tgtNodes.resize( elem->NbNodes() ); + for ( inode = 0; inode < tgtNodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); + tgtEditor.AddElement( tgtNodes, elemToCopy.Init( elem )); tgtEditor.myLastCreatedElems.Clear(); } } return nbAddedBnd; } + +//================================================================================ +/*! + * \brief Copy node position and set \a to node on the same geometry + */ +//================================================================================ + +void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, + const SMDS_MeshNode* to ) +{ + if ( !from || !to ) return; + + SMDS_PositionPtr pos = from->GetPosition(); + if ( !pos || from->getshapeId() < 1 ) return; + + switch ( pos->GetTypeOfPosition() ) + { + case SMDS_TOP_3DSPACE: break; + + case SMDS_TOP_FACE: + { + const SMDS_FacePosition* fPos = static_cast< const SMDS_FacePosition* >( pos ); + GetMeshDS()->SetNodeOnFace( to, from->getshapeId(), + fPos->GetUParameter(), fPos->GetVParameter() ); + break; + } + case SMDS_TOP_EDGE: + { + // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!! + const SMDS_EdgePosition* ePos = static_cast< const SMDS_EdgePosition* >( pos ); + GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() ); + break; + } + case SMDS_TOP_VERTEX: + { + GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() ); + break; + } + case SMDS_TOP_UNSPEC: + default:; + } +}