X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=cea314220460932062e7b7bd972eeced069adae7;hp=b45e0117bb235707b4499f60e482f6619c487794;hb=441a2df90cb97ea7d035771a49e28dc53469e3d6;hpb=df9cc07c95bbe75654ed43634939a133ccebe2f6 diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index b45e0117b..cea314220 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 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 @@ -26,29 +26,26 @@ #include "SMESH_MeshEditor.hxx" -#include "SMDS_FaceOfNodes.hxx" -#include "SMDS_VolumeTool.hxx" +#include "SMDS_Downward.hxx" #include "SMDS_EdgePosition.hxx" +#include "SMDS_FaceOfNodes.hxx" #include "SMDS_FacePosition.hxx" -#include "SMDS_SpacePosition.hxx" -#include "SMDS_MeshGroup.hxx" #include "SMDS_LinearEdge.hxx" -#include "SMDS_Downward.hxx" +#include "SMDS_MeshGroup.hxx" #include "SMDS_SetIterator.hxx" - +#include "SMDS_SpacePosition.hxx" +#include "SMDS_VolumeTool.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" - #include "SMESH_Algo.hxx" #include "SMESH_ControlsDef.hxx" #include "SMESH_Group.hxx" +#include "SMESH_Mesh.hxx" #include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_OctreeNode.hxx" #include "SMESH_subMesh.hxx" -#include - #include "utilities.h" #include "chrono.hxx" @@ -73,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -95,26 +93,19 @@ #include #include +#include #include #include +#include + +#include "SMESH_TryCatch.hxx" // include after OCCT headers! #define cast2Node(elem) static_cast( elem ) using namespace std; using namespace SMESH::Controls; -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 //purpose : @@ -125,6 +116,18 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) { } +//================================================================================ +/*! + * \brief Return mesh DS + */ +//================================================================================ + +SMESHDS_Mesh * SMESH_MeshEditor::GetMeshDS() +{ + return myMesh->GetMeshDS(); +} + + //================================================================================ /*! * \brief Clears myLastCreatedNodes and myLastCreatedElems @@ -133,10 +136,44 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) void SMESH_MeshEditor::ClearLastCreated() { - myLastCreatedNodes.Clear(); - myLastCreatedElems.Clear(); + SMESHUtils::FreeVector( myLastCreatedElems ); + SMESHUtils::FreeVector( myLastCreatedNodes ); } +//================================================================================ +/*! + * \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; +} //======================================================================= /*! @@ -146,18 +183,16 @@ void SMESH_MeshEditor::ClearLastCreated() 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] ); @@ -190,14 +225,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] ); @@ -285,6 +327,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: @@ -307,17 +359,17 @@ 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:; } - if ( e ) myLastCreatedElems.Append( e ); + if ( e ) myLastCreatedElems.push_back( e ); return e; } @@ -327,10 +379,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() ); @@ -341,7 +391,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs else return 0; } - return AddElement( nodes, type, isPoly, ID ); + return AddElement( nodes, features ); } //======================================================================= @@ -353,8 +403,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs int SMESH_MeshEditor::Remove (const list< int >& theIDs, const bool isNodes ) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); SMESHDS_Mesh* aMesh = GetMeshDS(); set< SMESH_subMesh *> smmap; @@ -415,31 +464,26 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs, //================================================================================ /*! - * \brief Create 0D elements on all nodes of the given object except those - * nodes on which a 0D element already exists. + * \brief Create 0D elements on all nodes of the given object. * \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 + * \param duplicateElements - to add one more 0D element to a node or not */ //================================================================================ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements, - TIDSortedElemSet& all0DElems ) + TIDSortedElemSet& all0DElems, + const bool duplicateElements ) { 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 ); + elemIt = SMESHUtils::elemSetIterator( elements ); } while ( elemIt->more() ) @@ -450,12 +494,13 @@ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& eleme { 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() ); + if ( duplicateElements || !it0D->more() ) + { + myLastCreatedElems.push_back( GetMeshDS()->Add0DElement( n )); + all0DElems.insert( myLastCreatedElems.back() ); } + while ( it0D->more() ) + all0DElems.insert( it0D->next() ); } } } @@ -468,8 +513,7 @@ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& eleme int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); SMESHDS_Mesh * aMesh = GetMeshDS(); if ( aMesh->ShapeToMesh().IsNull() ) @@ -636,20 +680,18 @@ static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1, bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, const SMDS_MeshElement * theTria2 ) { - MESSAGE("InverseDiag"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); - if (!theTria1 || !theTria2) + if ( !theTria1 || !theTria2 || + !dynamic_cast( theTria1 ) || + !dynamic_cast( theTria2 ) || + theTria1->GetType() != SMDSAbs_Face || + theTria2->GetType() != SMDSAbs_Face ) return false; - const SMDS_VtkFace* F1 = dynamic_cast( theTria1 ); - if (!F1) return false; - const SMDS_VtkFace* F2 = dynamic_cast( theTria2 ); - if (!F2) return false; if ((theTria1->GetEntityType() == SMDSEntity_Triangle) && - (theTria2->GetEntityType() == SMDSEntity_Triangle)) { - + (theTria2->GetEntityType() == SMDSEntity_Triangle)) + { // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | // |/ | | \| @@ -763,9 +805,9 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, gp_Pnt xyz; if ( F.IsNull() ) { - xyz = ( SMESH_TNodeXYZ( nodes[3] ) + - SMESH_TNodeXYZ( nodes[4] ) + - SMESH_TNodeXYZ( nodes[5] )) / 3.; + xyz = ( SMESH_NodeXYZ( nodes[3] ) + + SMESH_NodeXYZ( nodes[4] ) + + SMESH_NodeXYZ( nodes[5] )) / 3.; } else { @@ -838,19 +880,16 @@ static bool findTriangles(const SMDS_MeshNode * theNode1, bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1, const SMDS_MeshNode * theNode2) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - MESSAGE( "::InverseDiag()" ); + ClearLastCreated(); const SMDS_MeshElement *tr1, *tr2; if ( !findTriangles( theNode1, theNode2, tr1, tr2 )) return false; - const SMDS_VtkFace* F1 = dynamic_cast( tr1 ); - if (!F1) return false; - const SMDS_VtkFace* F2 = dynamic_cast( tr2 ); - if (!F2) return false; + if ( !dynamic_cast( tr1 ) || + !dynamic_cast( tr2 )) + return false; + if ((tr1->GetEntityType() == SMDSEntity_Triangle) && (tr2->GetEntityType() == SMDSEntity_Triangle)) { @@ -961,37 +1000,33 @@ bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [], bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, const SMDS_MeshNode * theNode2) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - MESSAGE( "::DeleteDiag()" ); + ClearLastCreated(); const SMDS_MeshElement *tr1, *tr2; if ( !findTriangles( theNode1, theNode2, tr1, tr2 )) return false; - const SMDS_VtkFace* F1 = dynamic_cast( tr1 ); - if (!F1) return false; - const SMDS_VtkFace* F2 = dynamic_cast( tr2 ); - if (!F2) return false; + if ( !dynamic_cast( tr1 ) || + !dynamic_cast( tr2 )) + return false; + SMESHDS_Mesh * aMesh = GetMeshDS(); if ((tr1->GetEntityType() == SMDSEntity_Triangle) && - (tr2->GetEntityType() == SMDSEntity_Triangle)) { - + (tr2->GetEntityType() == SMDSEntity_Triangle)) + { const SMDS_MeshNode* aNodes [ 4 ]; if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 )) return false; const SMDS_MeshElement* newElem = 0; newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] ); - myLastCreatedElems.Append(newElem); + myLastCreatedElems.push_back(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 ); @@ -1035,13 +1070,13 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, const SMDS_MeshElement* newElem = 0; newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3], aNodes[4], aNodes[5], aNodes[6], aNodes[7]); - myLastCreatedElems.Append(newElem); + myLastCreatedElems.push_back(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 ); @@ -1058,9 +1093,7 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) { - MESSAGE("Reorient"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); if (!theElem) return false; @@ -1075,8 +1108,7 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) const SMDSAbs_EntityType geomType = theElem->GetEntityType(); if ( geomType == SMDSEntity_Polyhedra ) // polyhedron { - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( theElem ); + const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( theElem ); if (!aPolyedre) { MESSAGE("Warning: bad volumic element"); return false; @@ -1100,12 +1132,12 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) else // other elements { vector nodes( theElem->begin_nodes(), theElem->end_nodes() ); - const std::vector& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType ); + const std::vector& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() ); if ( interlace.empty() ) { - std::reverse( nodes.begin(), nodes.end() ); // polygon + std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case } - else if ( interlace.size() > 1 ) + else { SMDS_MeshCell::applyInterlace( interlace, nodes ); } @@ -1119,7 +1151,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 oriented according to + * \param theFace - one of \a theFaces that should be oriented according to * \a theDirection and whose orientation defines orientation of other faces * \return number of reoriented faces. */ @@ -1134,7 +1166,7 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, if ( theFaces.empty() ) { - SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true); + SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=true*/); while ( fIt->more() ) theFaces.insert( theFaces.end(), fIt->next() ); } @@ -1229,7 +1261,7 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, } if ( otherFace && otherFace != theFace) { - // link must be reverse in otherFace if orientation ot otherFace + // link must be reverse in otherFace if orientation to otherFace // is same as that of theFace if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 ) { @@ -1265,7 +1297,7 @@ int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, if ( theFaces.empty() ) faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face ); else - faceIt = elemSetIterator( theFaces ); + faceIt = SMESHUtils::elemSetIterator( theFaces ); vector< const SMDS_MeshNode* > faceNodes; TIDSortedElemSet checkedVolumes; @@ -1278,7 +1310,7 @@ int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, if ( face->GetType() != SMDSAbs_Face ) continue; - const int nbCornersNodes = face->NbCornerNodes(); + const size_t nbCornersNodes = face->NbCornerNodes(); faceNodes.assign( face->begin_nodes(), face->end_nodes() ); checkedVolumes.clear(); @@ -1294,7 +1326,7 @@ int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, // is volume adjacent? bool allNodesCommon = true; - for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN ) + for ( size_t iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN ) allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 ); if ( !allNodesCommon ) continue; @@ -1314,7 +1346,7 @@ int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, for ( int i = 0; i < 2; ++i ) { const SMDS_MeshNode* n = facetNodes[ i*iQ ]; - for ( int iN = 0; iN < nbCornersNodes; ++iN ) + for ( size_t iN = 0; iN < nbCornersNodes; ++iN ) if ( faceNodes[ iN ] == n ) { iNN[ i ] = iN; @@ -1354,17 +1386,17 @@ static double getBadRate (const SMDS_MeshElement* theElem, bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, SMESH::Controls::NumericalFunctorPtr theCrit) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); if ( !theCrit.get() ) return false; - SMESHDS_Mesh * aMesh = GetMeshDS(); - + SMESHDS_Mesh * aMesh = GetMeshDS(); Handle(Geom_Surface) surface; SMESH_MesherHelper helper( *GetMesh() ); + myLastCreatedElems.reserve( theElems.size() * 2 ); + TIDSortedElemSet::iterator itElem; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { @@ -1391,7 +1423,7 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, const SMDS_MeshElement* newElem1 = 0; const SMDS_MeshElement* newElem2 = 0; - if ( !elem->IsQuadratic() ) // split liner quadrangle + if ( !elem->IsQuadratic() ) // split linear quadrangle { // for MaxElementLength2D functor we return minimum diagonal for splitting, // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) @@ -1433,8 +1465,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, // care of a new element - myLastCreatedElems.Append(newElem1); - myLastCreatedElems.Append(newElem2); + myLastCreatedElems.push_back(newElem1); + myLastCreatedElems.push_back(newElem2); AddToSameGroups( newElem1, elem, aMesh ); AddToSameGroups( newElem2, elem, aMesh ); @@ -1451,27 +1483,27 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, //======================================================================= /*! * \brief Split each of given quadrangles into 4 triangles. - * \param theElems - The faces to be splitted. If empty all faces are split. + * \param theElems - The faces to be split. If empty all faces are split. */ //======================================================================= void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); + myLastCreatedElems.reserve( theElems.size() * 4 ); SMESH_MesherHelper helper( *GetMesh() ); helper.SetElementsOnShape( true ); SMDS_ElemIteratorPtr faceIt; if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face); - else faceIt = elemSetIterator( theElems ); + else faceIt = SMESHUtils::elemSetIterator( theElems ); bool checkUV; gp_XY uv [9]; uv[8] = gp_XY(0,0); gp_XYZ xyz[9]; vector< const SMDS_MeshNode* > nodes; - SMESHDS_SubMesh* subMeshDS; + SMESHDS_SubMesh* subMeshDS = 0; TopoDS_Face F; Handle(Geom_Surface) surface; TopLoc_Location loc; @@ -1522,7 +1554,7 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems) if ( F.IsNull() ) { for ( ; iN < nodes.size(); ++iN ) - xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] ); + xyz[ iN ] = SMESH_NodeXYZ( nodes[ iN ] ); for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] ); @@ -1549,25 +1581,25 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems) nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0, uv[8].X(), uv[8].Y() ); - myLastCreatedNodes.Append( nCentral ); + myLastCreatedNodes.push_back( 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 )); + GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false ); + 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 ); + myLastCreatedElems.push_back( tria ); } } } @@ -1580,8 +1612,7 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems) int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, SMESH::Controls::NumericalFunctorPtr theCrit) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); if (!theCrit.get()) return -1; @@ -1865,6 +1896,7 @@ namespace break; case SMDSEntity_Penta: case SMDSEntity_Quad_Penta: + case SMDSEntity_BiQuad_Penta: connVariants = thePentaTo3; nbTet = 3; nbVariants = 6; break; default: @@ -1878,7 +1910,7 @@ namespace if ( hasAdjacentSplits && method._nbSplits > 0 ) { bool facetCreated = true; - for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) + for ( size_t iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) { list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin(); for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet ) @@ -2083,7 +2115,7 @@ namespace // No adjacent prisms. Select a variant with a best aspect ratio. - double badness[2] = { 0, 0 }; + 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 ) @@ -2192,6 +2224,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, // map face of volume to it's baricenrtic node map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; double bc[3]; + vector splitVols; TFacetOfElem::const_iterator elem2facet = theElems.begin(); for ( ; elem2facet != theElems.end(); ++elem2facet ) @@ -2246,7 +2279,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, volTool.GetBaryCenter( bc[0], bc[1], bc[2] ); SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] ); nodes.push_back( gcNode ); - newNodes.Append( gcNode ); + newNodes.push_back( gcNode ); } if ( !splitMethod._faceBaryNode.empty() ) { @@ -2260,29 +2293,29 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, if ( !f_n->second ) { volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] ); - newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] )); + newNodes.push_back( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] )); } nodes.push_back( iF_n->second = f_n->second ); } } // make new volumes - vector splitVols( splitMethod._nbSplits ); // splits of a volume + 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] ])); + newElems.push_back( 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] ])); + newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ], + nodes[ volConn[1] ], + nodes[ volConn[2] ], + nodes[ volConn[3] ], + nodes[ volConn[4] ], + nodes[ volConn[5] ])); ReplaceElemInGroups( elem, splitVols, GetMeshDS() ); @@ -2326,7 +2359,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, if ( fSubMesh ) // update position of the bary node on geometry { if ( subMesh ) - subMesh->RemoveNode( baryNode, false ); + subMesh->RemoveNode( baryNode ); GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() ); const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() ); if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE ) @@ -2335,7 +2368,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, gp_XY uv( 1e100, 1e100 ); double distXYZ[4]; if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode, - uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) && + uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) && uv.X() < 1e100 ) { // node is too far from the surface @@ -2348,7 +2381,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, } else { - // among possible triangles create ones discribed by split method + // among possible triangles create ones described by split method const int* nInd = volTool.GetFaceNodesIndices( iF ); int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); int iCom = 0; // common node of triangle faces to split into @@ -2384,12 +2417,12 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, volNodes[ facet->_n3 ])); } } - for ( int i = 0; i < triangles.size(); ++i ) + for ( size_t i = 0; i < triangles.size(); ++i ) { - if ( !triangles[i] ) continue; + if ( !triangles[ i ]) continue; if ( fSubMesh ) - fSubMesh->AddElement( triangles[i]); - newElems.Append( triangles[i] ); + fSubMesh->AddElement( triangles[ i ]); + newElems.push_back( triangles[ i ]); } ReplaceElemInGroups( face, triangles, GetMeshDS() ); GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false ); @@ -2407,7 +2440,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, GetMeshDS()->RemoveNode( volNodes[i] ); } } // loop on volumes to split - + myLastCreatedNodes = newNodes; myLastCreatedElems = newElems; } @@ -2426,7 +2459,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, const gp_Ax1& theFacetNormal, TFacetOfElem & theFacets) { - #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): " +#define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): " // Find a hexa closest to the location of theFacetNormal @@ -2474,7 +2507,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, // Fill theFacets starting from facetID of startHex - // facets used for seach of volumes adjacent to already treated ones + // facets used for searching of volumes adjacent to already treated ones typedef pair< TFacetOfElem::iterator, int > TElemFacets; typedef map< TVolumeFaceKey, TElemFacets > TFacetMap; TFacetMap facetsToCheck; @@ -2482,7 +2515,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, set facetNodes; const SMDS_MeshElement* curHex; - const bool allHex = ( theHexas.size() == myMesh->NbHexas() ); + const bool allHex = ((int) theHexas.size() == myMesh->NbHexas() ); while ( startHex ) { @@ -2572,7 +2605,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, startHex = curHex; - // find a facet of startHex to split + // find a facet of startHex to split set lateralNodes; vTool.GetFaceNodes( lateralFacet, lateralNodes ); @@ -2602,6 +2635,188 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, 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] ); + } + } } //======================================================================= @@ -2683,7 +2898,7 @@ void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* 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 ) + for ( size_t i = 0; i < elemToAdd.size(); ++i ) group->SMDSGroup().Add( elemToAdd[ i ] ); } } @@ -2698,25 +2913,21 @@ void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, const bool the13Diag) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - MESSAGE( "::QuadToTri()" ); - - SMESHDS_Mesh * aMesh = GetMeshDS(); + ClearLastCreated(); + myLastCreatedElems.reserve( theElems.size() * 2 ); + SMESHDS_Mesh * aMesh = GetMeshDS(); Handle(Geom_Surface) surface; 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 ) + if ( !elem || elem->GetGeomType() != SMDSGeom_QUADRANGLE ) continue; - bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8; - if(!isquad) continue; - if(elem->NbNodes()==4) { + if ( elem->NbNodes() == 4 ) { // retrieve element nodes const SMDS_MeshNode* aNodes [4]; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); @@ -2735,24 +2946,23 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] ); } - myLastCreatedElems.Append(newElem1); - myLastCreatedElems.Append(newElem2); + myLastCreatedElems.push_back(newElem1); + myLastCreatedElems.push_back(newElem2); // put a new triangle on the same shape and add to the same groups if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem1, aShapeId ); - aMesh->SetMeshElementOnShape( newElem2, aShapeId ); - } + { + aMesh->SetMeshElementOnShape( newElem1, aShapeId ); + aMesh->SetMeshElementOnShape( newElem2, aShapeId ); + } AddToSameGroups( newElem1, elem, aMesh ); AddToSameGroups( newElem2, elem, aMesh ); - //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true); aMesh->RemoveElement( elem ); } // Quadratic quadrangle - if( elem->NbNodes()==8 && elem->IsQuadratic() ) { - + else if ( elem->NbNodes() >= 8 ) + { // get surface elem is on int aShapeId = FindShape( elem ); if ( aShapeId != helper.GetSubShapeID() ) { @@ -2768,61 +2978,43 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, } } - const SMDS_MeshNode* aNodes [8]; - const SMDS_MeshNode* inFaceNode = 0; + const SMDS_MeshNode* aNodes [9]; aNodes[8] = 0; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) { - aNodes[ i++ ] = static_cast( itN->next() ); - if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() && - aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) - { - inFaceNode = aNodes[ i-1 ]; - } - } + for ( int i = 0; itN->more(); ++i ) + aNodes[ i ] = static_cast( itN->next() ); - // find middle point for (0,1,2,3) - // and create a node in this point; - gp_XYZ p( 0,0,0 ); - if ( surface.IsNull() ) { - for(i=0; i<4; i++) - p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); - p /= 4; - } - else { - TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() ); - gp_XY uv( 0,0 ); - for(i=0; i<4; i++) - uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode ); - uv /= 4.; - p = surface->Value( uv.X(), uv.Y() ).XYZ(); + const SMDS_MeshNode* centrNode = aNodes[8]; + if ( centrNode == 0 ) + { + centrNode = helper.GetCentralNode( aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7], + surface.IsNull() ); + myLastCreatedNodes.push_back(centrNode); } - const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); - myLastCreatedNodes.Append(newN); // create a new element const SMDS_MeshElement* newElem1 = 0; const SMDS_MeshElement* newElem2 = 0; if ( the13Diag ) { newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], - aNodes[6], aNodes[7], newN ); + aNodes[6], aNodes[7], centrNode ); newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1], - newN, aNodes[4], aNodes[5] ); + centrNode, aNodes[4], aNodes[5] ); } else { newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], - aNodes[7], aNodes[4], newN ); + aNodes[7], aNodes[4], centrNode ); newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2], - newN, aNodes[5], aNodes[6] ); + centrNode, aNodes[5], aNodes[6] ); } - myLastCreatedElems.Append(newElem1); - myLastCreatedElems.Append(newElem2); + myLastCreatedElems.push_back(newElem1); + myLastCreatedElems.push_back(newElem2); // put a new triangle on the same shape and add to the same groups if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem1, aShapeId ); - aMesh->SetMeshElementOnShape( newElem2, aShapeId ); - } + { + aMesh->SetMeshElementOnShape( newElem1, aShapeId ); + aMesh->SetMeshElementOnShape( newElem2, aShapeId ); + } AddToSameGroups( newElem1, elem, aMesh ); AddToSameGroups( newElem2, elem, aMesh ); aMesh->RemoveElement( elem ); @@ -2940,10 +3132,8 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, SMESH::Controls::NumericalFunctorPtr theCrit, const double theMaxAngle) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - MESSAGE( "::TriToQuad()" ); + ClearLastCreated(); + myLastCreatedElems.reserve( theElems.size() / 2 ); if ( !theCrit.get() ) return false; @@ -3049,7 +3239,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, if ( startElem ) { // Get candidates to be fused const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0; - const SMESH_TLink *link12, *link13; + const SMESH_TLink *link12 = 0, *link13 = 0; startElem = 0; ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() ); set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ]; @@ -3127,7 +3317,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, { const SMDS_MeshElement* newElem = 0; newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] ); - myLastCreatedElems.Append(newElem); + myLastCreatedElems.push_back(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) @@ -3158,7 +3348,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, else newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], aNodes[4], aNodes[5], aNodes[6], aNodes[7]); - myLastCreatedElems.Append(newElem); + myLastCreatedElems.push_back(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) @@ -3181,7 +3371,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, if ( tr1->NbNodes() == 3 ) { const SMDS_MeshElement* newElem = 0; newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] ); - myLastCreatedElems.Append(newElem); + myLastCreatedElems.push_back(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) @@ -3212,7 +3402,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, else newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], aNodes[4], aNodes[5], aNodes[6], aNodes[7]); - myLastCreatedElems.Append(newElem); + myLastCreatedElems.push_back(newElem); AddToSameGroups( newElem, tr1, aMesh ); int aShapeId = tr1->getshapeId(); if ( aShapeId ) @@ -3240,286 +3430,6 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, return true; } - -/*#define DUMPSO(txt) \ -// cout << txt << endl; -//============================================================================= -// -// -// -//============================================================================= -static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] ) -{ -if ( i1 == i2 ) -return; -int tmp = idNodes[ i1 ]; -idNodes[ i1 ] = idNodes[ i2 ]; -idNodes[ i2 ] = tmp; -gp_Pnt Ptmp = P[ i1 ]; -P[ i1 ] = P[ i2 ]; -P[ i2 ] = Ptmp; -DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")"); -} - -//======================================================================= -//function : SortQuadNodes -//purpose : Set 4 nodes of a quadrangle face in a good order. -// Swap 1<->2 or 2<->3 nodes and correspondingly return -// 1 or 2 else 0. -//======================================================================= - -int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh, -int idNodes[] ) -{ - gp_Pnt P[4]; - int i; - for ( i = 0; i < 4; i++ ) { - const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] ); - if ( !n ) return 0; - P[ i ].SetCoord( n->X(), n->Y(), n->Z() ); - } - - gp_Vec V1(P[0], P[1]); - gp_Vec V2(P[0], P[2]); - gp_Vec V3(P[0], P[3]); - - gp_Vec Cross1 = V1 ^ V2; - gp_Vec Cross2 = V2 ^ V3; - - i = 0; - if (Cross1.Dot(Cross2) < 0) - { - Cross1 = V2 ^ V1; - Cross2 = V1 ^ V3; - - if (Cross1.Dot(Cross2) < 0) - i = 2; - else - i = 1; - swap ( i, i + 1, idNodes, P ); - - // for ( int ii = 0; ii < 4; ii++ ) { - // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); - // DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); - // } - } - return i; -} - -//======================================================================= -//function : SortHexaNodes -//purpose : Set 8 nodes of a hexahedron in a good order. -// Return success status -//======================================================================= - -bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, - int idNodes[] ) -{ - gp_Pnt P[8]; - int i; - DUMPSO( "INPUT: ========================================"); - for ( i = 0; i < 8; i++ ) { - const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] ); - if ( !n ) return false; - P[ i ].SetCoord( n->X(), n->Y(), n->Z() ); - DUMPSO( i << "(" << idNodes[i] <<") : "<X()<<" "<Y()<<" "<Z()); - } - DUMPSO( "========================================"); - - - set faceNodes; // ids of bottom face nodes, to be found - set checkedId1; // ids of tried 2-nd nodes - Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane - const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane - int iMin, iLoop1 = 0; - - // Loop to try the 2-nd nodes - - while ( leastDist > DBL_MIN && ++iLoop1 < 8 ) - { - // Find not checked 2-nd node - for ( i = 1; i < 8; i++ ) - if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) { - int id1 = idNodes[i]; - swap ( 1, i, idNodes, P ); - checkedId1.insert ( id1 ); - break; - } - - // Find the 3-d node so that 1-2-3 triangle to be on a hexa face, - // ie that all but meybe one (id3 which is on the same face) nodes - // lay on the same side from the triangle plane. - - bool manyInPlane = false; // more than 4 nodes lay in plane - int iLoop2 = 0; - while ( ++iLoop2 < 6 ) { - - // get 1-2-3 plane coeffs - Standard_Real A, B, C, D; - gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); - if ( N.SquareMagnitude() > gp::Resolution() ) - { - gp_Pln pln ( P[0], N ); - pln.Coefficients( A, B, C, D ); - - // find the node (iMin) closest to pln - Standard_Real dist[ 8 ], minDist = DBL_MAX; - set idInPln; - for ( i = 3; i < 8; i++ ) { - dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D; - if ( fabs( dist[i] ) < minDist ) { - minDist = fabs( dist[i] ); - iMin = i; - } - if ( fabs( dist[i] ) <= tol ) - idInPln.insert( idNodes[i] ); - } - - // there should not be more than 4 nodes in bottom plane - if ( idInPln.size() > 1 ) - { - DUMPSO( "### idInPln.size() = " << idInPln.size()); - // idInPlane does not contain the first 3 nodes - if ( manyInPlane || idInPln.size() == 5) - return false; // all nodes in one plane - manyInPlane = true; - - // set the 1-st node to be not in plane - for ( i = 3; i < 8; i++ ) { - if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) { - DUMPSO( "### Reset 0-th node"); - swap( 0, i, idNodes, P ); - break; - } - } - - // reset to re-check second nodes - leastDist = DBL_MAX; - faceNodes.clear(); - checkedId1.clear(); - iLoop1 = 0; - break; // from iLoop2; - } - - // check that the other 4 nodes are on the same side - bool sameSide = true; - bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.; - for ( i = 3; sameSide && i < 8; i++ ) { - if ( i != iMin ) - sameSide = ( isNeg == dist[i] <= 0.); - } - - // keep best solution - if ( sameSide && minDist < leastDist ) { - leastDist = minDist; - faceNodes.clear(); - faceNodes.insert( idNodes[ 1 ] ); - faceNodes.insert( idNodes[ 2 ] ); - faceNodes.insert( idNodes[ iMin ] ); - DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ] - << " leastDist = " << leastDist); - if ( leastDist <= DBL_MIN ) - break; - } - } - - // set next 3-d node to check - int iNext = 2 + iLoop2; - if ( iNext < 8 ) { - DUMPSO( "Try 2-nd"); - swap ( 2, iNext, idNodes, P ); - } - } // while ( iLoop2 < 6 ) - } // iLoop1 - - if ( faceNodes.empty() ) return false; - - // Put the faceNodes in proper places - for ( i = 4; i < 8; i++ ) { - if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) { - // find a place to put - int iTo = 1; - while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() ) - iTo++; - DUMPSO( "Set faceNodes"); - swap ( iTo, i, idNodes, P ); - } - } - - - // Set nodes of the found bottom face in good order - DUMPSO( " Found bottom face: "); - i = SortQuadNodes( theMesh, idNodes ); - if ( i ) { - gp_Pnt Ptmp = P[ i ]; - P[ i ] = P[ i+1 ]; - P[ i+1 ] = Ptmp; - } - // else - // for ( int ii = 0; ii < 4; ii++ ) { - // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); - // DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); - // } - - // Gravity center of the top and bottom faces - gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.; - gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.; - - // Get direction from the bottom to the top face - gp_Vec upDir ( aGCb, aGCt ); - Standard_Real upDirSize = upDir.Magnitude(); - if ( upDirSize <= gp::Resolution() ) return false; - upDir / upDirSize; - - // Assure that the bottom face normal points up - gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); - Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) ); - if ( Nb.Dot( upDir ) < 0 ) { - DUMPSO( "Reverse bottom face"); - swap( 1, 3, idNodes, P ); - } - - // Find 5-th node - the one closest to the 1-st among the last 4 nodes. - Standard_Real minDist = DBL_MAX; - for ( i = 4; i < 8; i++ ) { - // projection of P[i] to the plane defined by P[0] and upDir - gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] )))); - Standard_Real sqDist = P[0].SquareDistance( Pp ); - if ( sqDist < minDist ) { - minDist = sqDist; - iMin = i; - } - } - DUMPSO( "Set 4-th"); - swap ( 4, iMin, idNodes, P ); - - // Set nodes of the top face in good order - DUMPSO( "Sort top face"); - i = SortQuadNodes( theMesh, &idNodes[4] ); - if ( i ) { - i += 4; - gp_Pnt Ptmp = P[ i ]; - P[ i ] = P[ i+1 ]; - P[ i+1 ] = Ptmp; - } - - // Assure that direction of the top face normal is from the bottom face - gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) ); - Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) ); - if ( Nt.Dot( upDir ) < 0 ) { - DUMPSO( "Reverse top face"); - swap( 5, 7, idNodes, P ); - } - - // DUMPSO( "OUTPUT: ========================================"); - // for ( i = 0; i < 8; i++ ) { - // float *p = ugrid->GetPoint(idNodes[i]); - // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]); - // } - - return true; -}*/ - //================================================================================ /*! * \brief Return nodes linked to the given one @@ -3725,10 +3635,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, double theTgtAspectRatio, const bool the2D) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()"); + ClearLastCreated(); if ( theTgtAspectRatio < 1.0 ) theTgtAspectRatio = 1.0; @@ -3777,7 +3684,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, Handle(Geom_Surface) surface; SMESHDS_SubMesh* faceSubMesh = 0; TopoDS_Face face; - double fToler2 = 0, f,l; + double fToler2 = 0; double u1 = 0, u2 = 0, v1 = 0, v2 = 0; bool isUPeriodic = false, isVPeriodic = false; if ( *fId ) @@ -3788,11 +3695,11 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, fToler2 = BRep_Tool::Tolerance( face ); fToler2 *= fToler2 * 10.; isUPeriodic = surface->IsUPeriodic(); - if ( isUPeriodic ) - surface->UPeriod(); + // if ( isUPeriodic ) + // surface->UPeriod(); isVPeriodic = surface->IsVPeriodic(); - if ( isVPeriodic ) - surface->VPeriod(); + // if ( isVPeriodic ) + // surface->VPeriod(); surface->Bounds( u1, u2, v1, v2 ); helper.SetSubShape( face ); } @@ -3851,9 +3758,9 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, { // check if all faces around the node are on faceSubMesh // because a node on edge may be bound to face - SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); bool all = true; if ( faceSubMesh ) { + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); while ( eIt->more() && all ) { const SMDS_MeshElement* e = eIt->next(); all = faceSubMesh->Contains( e ); @@ -3921,7 +3828,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // } if ( project ) { // compute new UV gp_XY newUV; - gp_Pnt pNode = SMESH_TNodeXYZ( node ); + gp_Pnt pNode = SMESH_NodeXYZ( node ); if ( !getClosestUV( projector, pNode, newUV )) { MESSAGE("Node Projection Failed " << node); } @@ -3934,7 +3841,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // if ( posType != SMDS_TOP_3DSPACE ) // dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); // if ( dist2 < dist1 ) - uv = newUV; + uv = newUV; } } // store UV in the map @@ -4136,18 +4043,18 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, } } if ( maxRatio <= theTgtAspectRatio ) { - MESSAGE("-- quality achived --"); + //MESSAGE("-- quality achieved --"); break; } if (it+1 == theNbIterations) { - MESSAGE("-- Iteration limit exceeded --"); + //MESSAGE("-- Iteration limit exceeded --"); } } // smoothing iterations - MESSAGE(" Face id: " << *fId << - " Nb iterstions: " << it << - " Displacement: " << maxDisplacement << - " Aspect Ratio " << maxRatio); + // MESSAGE(" Face id: " << *fId << + // " Nb iterstions: " << it << + // " Displacement: " << maxDisplacement << + // " Aspect Ratio " << maxRatio); // --------------------------------------- // new nodes positions are computed, @@ -4176,7 +4083,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, const SMDS_MeshElement* QF = *elemIt; if ( QF->IsQuadratic() ) { - nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ), + nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesIterator() ), SMDS_MeshElement::iterator() ); nodes.push_back( nodes[0] ); gp_Pnt xyz; @@ -4190,9 +4097,9 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, xyz = surface->Value( uv.X(), uv.Y() ); } else { - xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] )); + xyz = 0.5 * ( SMESH_NodeXYZ( nodes[i-1] ) + SMESH_NodeXYZ( nodes[i+1] )); } - if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol ) + if (( SMESH_NodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol ) // we have to move a medium node aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() ); } @@ -4220,8 +4127,8 @@ namespace const int iNotSame) { - SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; - SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; + SMESH_NodeXYZ pP = prevNodes[ iNotSame ]; + SMESH_NodeXYZ pN = nextNodes[ iNotSame ]; gp_XYZ extrDir( pN - pP ), faceNorm; SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); @@ -4263,10 +4170,9 @@ namespace void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, const vector & newNodesItVec, list& newElems, - const int nbSteps, + const size_t nbSteps, SMESH_SequenceOfElemPtr& srcElements) { - //MESSAGE("sweepElement " << nbSteps); SMESHDS_Mesh* aMesh = GetMeshDS(); const int nbNodes = elem->NbNodes(); @@ -4326,7 +4232,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 ); @@ -4363,7 +4269,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, std::swap( itNN[0], itNN[1] ); std::swap( prevNod[0], prevNod[1] ); std::swap( nextNod[0], nextNod[1] ); - isSingleNode.swap( isSingleNode[0], isSingleNode[1] ); + std::swap( isSingleNode[0], isSingleNode[1] ); if ( nbSame > 0 ) sames[0] = 1 - sames[0]; iNotSameNode = 1 - iNotSameNode; @@ -4379,8 +4285,19 @@ 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++ ) + for ( size_t iStep = 0; iStep < nbSteps; iStep++ ) { // get next nodes for ( iNode = 0; iNode < nbNodes; iNode++ ) @@ -4444,55 +4361,55 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, break; } case SMDSEntity_Triangle: // TRIANGLE ---> - { - if ( nbDouble > 0 ) break; - if ( nbSame == 0 ) // ---> pentahedron - aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], - nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] ); - - else if ( nbSame == 1 ) // ---> pyramid - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], - nextNod[ iAfterSame ], nextNod[ iBeforeSame ], - nextNod[ iSameNode ]); - - else // 2 same nodes: ---> tetrahedron - aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], - nextNod[ iNotSameNode ]); - break; - } + { + if ( nbDouble > 0 ) break; + if ( nbSame == 0 ) // ---> pentahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], + nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] ); + + else if ( nbSame == 1 ) // ---> pyramid + aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], + nextNod[ iAfterSame ], nextNod[ iBeforeSame ], + nextNod[ iSameNode ]); + + else // 2 same nodes: ---> tetrahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], + nextNod[ iNotSameNode ]); + break; + } case SMDSEntity_Quad_Edge: // sweep quadratic EDGE ---> + { + if ( nbSame == 2 ) + return; + if ( nbDouble+nbSame == 2 ) { - if ( nbSame == 2 ) - return; - if ( nbDouble+nbSame == 2 ) - { - if(nbSame==0) { // ---> quadratic quadrangle - aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], - prevNod[2], midlNod[1], nextNod[2], midlNod[0]); - } - else { //(nbSame==1) // ---> quadratic triangle - if(sames[0]==2) { - return; // medium node on axis - } - else if(sames[0]==0) - aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], - prevNod[2], midlNod[1], nextNod[2] ); - else // sames[0]==1 - aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0], - prevNod[2], nextNod[2], midlNod[0]); - } + if(nbSame==0) { // ---> quadratic quadrangle + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], + prevNod[2], midlNod[1], nextNod[2], midlNod[0]); } - else if ( nbDouble == 3 ) - { - if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle - aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], - prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]); + else { //(nbSame==1) // ---> quadratic triangle + if(sames[0]==2) { + return; // medium node on axis } + else if(sames[0]==0) + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], + prevNod[2], midlNod[1], nextNod[2] ); + else // sames[0]==1 + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0], + prevNod[2], nextNod[2], midlNod[0]); + } + } + else if ( nbDouble == 3 ) + { + if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], + prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]); } - else - return; - break; } + else + return; + break; + } case SMDSEntity_Quadrangle: { // sweep QUADRANGLE ---> if ( nbDouble > 0 ) break; @@ -4524,7 +4441,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, break; } case SMDSEntity_Quad_Triangle: // sweep (Bi)Quadratic TRIANGLE ---> - case SMDSEntity_BiQuad_Triangle: /* ??? */ { + case SMDSEntity_BiQuad_Triangle: /* ??? */ { if ( nbDouble+nbSame != 3 ) break; if(nbSame==0) { // ---> pentahedron with 15 nodes @@ -4576,7 +4493,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, else if(nbSame==1) { // ---> pyramid + pentahedron - can not be created since it is needed // additional middle node at the center of face - INFOS( " Sweep for face " << elem->GetID() << " can not be created" ); + //INFOS( " Sweep for face " << elem->GetID() << " can not be created" ); return; } else if( nbSame == 2 ) { @@ -4652,7 +4569,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, { 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 ); @@ -4677,21 +4594,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 ) @@ -4701,12 +4627,12 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - } // // try to create a polyherdal prism + } // try to create a polyherdal prism if ( aNewElem ) { newElems.push_back( aNewElem ); - myLastCreatedElems.Append(aNewElem); - srcElements.Append( elem ); + myLastCreatedElems.push_back(aNewElem); + srcElements.push_back( elem ); } // set new prev nodes @@ -4752,16 +4678,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const SMDS_MeshElement* el = 0; SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only while ( eIt->more() && nbInitElems < 2 ) { - el = eIt->next(); - SMDSAbs_ElementType type = el->GetType(); - if ( type == SMDSAbs_Volume || type < highType ) continue; + const SMDS_MeshElement* e = eIt->next(); + SMDSAbs_ElementType type = e->GetType(); + if ( type == SMDSAbs_Volume || + type < highType || + !elemSet.count(e)) + continue; if ( type > highType ) { nbInitElems = 0; - highType = type; + highType = type; } - nbInitElems += elemSet.count(el); + el = e; + ++nbInitElems; } - if ( nbInitElems < 2 ) { + if ( nbInitElems == 1 ) { bool NotCreateEdge = el && el->IsMediumNode(node); if(!NotCreateEdge) { vector newNodesItVec( 1, nList ); @@ -4774,6 +4704,8 @@ 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. + ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace; + TTElemOfElemListMap::iterator itElem = newElemsMap.begin(); TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) @@ -4790,19 +4722,19 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( !isQuadratic ) { if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back())) { - myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back())); - srcElements.Append( elem ); + myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back())); + srcElements.push_back( elem ); } } else { if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back(), vecNewNodes[ 2 ]->second.back())) { - myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back(), - vecNewNodes[ 2 ]->second.back())); - srcElements.Append( elem ); + myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back(), + vecNewNodes[ 2 ]->second.back())); + srcElements.push_back( elem ); } } } @@ -4830,14 +4762,14 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // 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() ); + myLastCreatedElems.push_back( edge = aMesh->AddEdge( n1, n2 )); // free link edge + srcElements.push_back( myLastCreatedElems.back() ); } n1 = vecNewNodes[ iNode ]->second.back(); n2 = vecNewNodes[ iNext ]->second.back(); if ( !aMesh->FindEdge( n1, n2 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling - srcElements.Append( edge ); + myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2 )); // new edge ceiling + srcElements.push_back( edge ); } } } @@ -4858,15 +4790,15 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // 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( elem ); + myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // free link edge + srcElements.push_back( 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( elem ); + myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge + srcElements.push_back( elem ); } } } @@ -4877,7 +4809,7 @@ 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; @@ -4900,9 +4832,9 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false ); int iF, nbF = vTool.NbFaces(); for ( iF = 0; iF < nbF; iF ++ ) { - if (vTool.IsFreeFace( iF ) && - vTool.GetFaceNodes( iF, faceNodeSet ) && - initNodeSet != faceNodeSet) // except an initial face + if ( vTool.IsFreeFace( iF ) && + vTool.GetFaceNodes( iF, faceNodeSet ) && + initNodeSet != faceNodeSet) // except an initial face { if ( nbSteps == 1 && faceNodeSet == topNodeSet ) continue; @@ -4911,11 +4843,12 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, 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])); @@ -4931,10 +4864,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; @@ -4957,8 +4891,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); else - myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ] )); + myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ] )); } } else if ( nbn == 4 ) ///// quadrangle @@ -4972,8 +4906,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); else - myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ], newOrder[ 3 ])); + myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ])); } } else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle @@ -4991,12 +4925,12 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); else - myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], - newOrder[ 1 ], - newOrder[ 2 ], - newOrder[ 3 ], - newOrder[ 4 ], - newOrder[ 5 ] )); + myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], + newOrder[ 1 ], + newOrder[ 2 ], + newOrder[ 3 ], + newOrder[ 4 ], + newOrder[ 5 ] )); } } else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle @@ -5017,10 +4951,10 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); else - myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ], newOrder[ 3 ], - newOrder[ 4 ], newOrder[ 5 ], - newOrder[ 6 ], newOrder[ 7 ])); + myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ], + newOrder[ 4 ], newOrder[ 5 ], + newOrder[ 6 ], newOrder[ 7 ])); } } else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle @@ -5042,11 +4976,11 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); else - myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ], newOrder[ 3 ], - newOrder[ 4 ], newOrder[ 5 ], - newOrder[ 6 ], newOrder[ 7 ], - newOrder[ 8 ])); + myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ], + newOrder[ 4 ], newOrder[ 5 ], + newOrder[ 6 ], newOrder[ 7 ], + newOrder[ 8 ])); } } else //////// polygon @@ -5061,12 +4995,12 @@ 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() )); } } - while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( *srcEdge ); + while ( srcElements.size() < myLastCreatedElems.size() ) + srcElements.push_back( *srcEdge ); } // loop on free faces @@ -5088,39 +5022,23 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, aFaceLastNodes.erase( vecNewNodes.back()->second.back() ); iF = lastVol.GetFaceIndex( aFaceLastNodes ); } - if ( iF >= 0 ) { + if ( iF >= 0 ) + { lastVol.SetExternalNormal(); const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); - int nbn = lastVol.NbFaceNodes( iF ); - // we do not use this->AddElement() because nodes are interlaced + const int nbn = lastVol.NbFaceNodes( iF ); vector nodeVec( nodes, nodes+nbn ); if ( !hasFreeLinks || !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) ) { - if ( nbn == 3 ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] )); - - else if ( nbn == 4 ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3])); - - else if ( nbn == 6 && isQuadratic ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5])); - else if ( nbn == 7 && isQuadratic ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5], nodes[6])); - else if ( nbn == 8 && isQuadratic ) - 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 ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7], - nodes[8])); - else - myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec )); + const vector& interlace = + SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn ); + SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec ); + + AddElement( nodeVec, anyFace.Init( elem )); - while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( elem ); + while ( srcElements.size() < myLastCreatedElems.size() ) + srcElements.push_back( elem ); } } } // loop on swept elements @@ -5140,13 +5058,17 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], const bool theMakeGroups, const bool theMakeWalls) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); + + setElemsFirst( theElemSets ); + myLastCreatedElems.reserve( theElemSets[0].size() * theNbSteps ); + myLastCreatedNodes.reserve( theElemSets[1].size() * theNbSteps ); // source elements for each generated one SMESH_SequenceOfElemPtr srcElems, srcNodes; + srcElems.reserve( theElemSets[0].size() ); + srcNodes.reserve( theElemSets[1].size() ); - MESSAGE( "RotationSweep()"); gp_Trsf aTrsf; aTrsf.SetRotation( theAxis, theAngle ); gp_Trsf aTrsf2; @@ -5165,7 +5087,6 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], myMesh->NbFaces(ORDER_QUADRATIC) + myMesh->NbVolumes(ORDER_QUADRATIC) ); // loop on theElemSets - setElemsFirst( theElemSets ); TIDSortedElemSet::iterator itElem; for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) { @@ -5181,7 +5102,6 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - // check if a node has been already sweeped const SMDS_MeshNode* node = cast2Node( itN->next() ); gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); @@ -5189,6 +5109,7 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], aXYZ.Coord( coord[0], coord[1], coord[2] ); bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + // check if a node has been already sweeped TNodeOfNodeListMapItr nIt = mapNewNodes.insert( make_pair( node, list() )).first; list& listNewNodes = nIt->second; @@ -5217,8 +5138,8 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], { aTrsf2.Transforms( coord[0], coord[1], coord[2] ); newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( node ); listNewNodes.push_back( newNode ); aTrsf2.Transforms( coord[0], coord[1], coord[2] ); } @@ -5227,8 +5148,8 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], } // create a corner node newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( node ); listNewNodes.push_back( newNode ); } else { @@ -5260,11 +5181,14 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], //purpose : standard construction //======================================================================= -SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep, - const int theNbSteps, - const int theFlags, - const double theTolerance): +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep, + const int theNbSteps, + const std::list& theScales, + const gp_XYZ* theBasePoint, + const int theFlags, + const double theTolerance): myDir( theStep ), + myBaseP( Precision::Infinite(), 0, 0 ), myFlags( theFlags ), myTolerance( theTolerance ), myElemsToUse( NULL ) @@ -5274,6 +5198,37 @@ SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep, for (int i=1; i<=theNbSteps; i++ ) mySteps->Append( stepSize ); + int nbScales = theScales.size(); + if ( nbScales > 0 ) + { + if ( IsLinearVariation() && nbScales < theNbSteps ) + { + myScales.reserve( theNbSteps ); + std::list::const_iterator scale = theScales.begin(); + double prevScale = 1.0; + for ( int iSc = 1; scale != theScales.end(); ++scale, ++iSc ) + { + int iStep = int( iSc / double( nbScales ) * theNbSteps + 0.5 ); + int stDelta = Max( 1, iStep - myScales.size()); + double scDelta = ( *scale - prevScale ) / stDelta; + for ( int iStep = 0; iStep < stDelta; ++iStep ) + { + myScales.push_back( prevScale + scDelta ); + prevScale = myScales.back(); + } + prevScale = *scale; + } + } + else + { + myScales.assign( theScales.begin(), theScales.end() ); + } + } + if ( theBasePoint ) + { + myBaseP = *theBasePoint; + } + if (( theFlags & EXTRUSION_FLAG_SEW ) && ( theTolerance > 0 )) { @@ -5342,12 +5297,38 @@ SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize, //======================================================================= //function : ExtrusParam::SetElementsToUse //purpose : stores elements to use for extrusion by normal, depending on -// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag +// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag; +// define myBaseP for scaling //======================================================================= -void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems ) +void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems, + const TIDSortedElemSet& nodes ) { myElemsToUse = ToUseInpElemsOnly() ? & elems : 0; + + if ( Precision::IsInfinite( myBaseP.X() )) // myBaseP not defined + { + myBaseP.SetCoord( 0.,0.,0. ); + TIDSortedElemSet newNodes; + + const TIDSortedElemSet* elemSets[] = { &elems, &nodes }; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + const TIDSortedElemSet& elements = *( elemSets[ is2ndSet ]); + TIDSortedElemSet::const_iterator itElem = elements.begin(); + for ( ; itElem != elements.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { + const SMDS_MeshElement* node = itN->next(); + if ( newNodes.insert( node ).second ) + myBaseP += SMESH_NodeXYZ( node ); + } + } + } + myBaseP /= newNodes.size(); + } } //======================================================================= @@ -5408,7 +5389,7 @@ makeNodesByDir( SMESHDS_Mesh* mesh, std::list & newNodes, const bool makeMediumNodes) { - gp_XYZ p = SMESH_TNodeXYZ( srcNode ); + gp_XYZ p = SMESH_NodeXYZ( srcNode ); int nbNodes = 0; for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps @@ -5417,6 +5398,41 @@ makeNodesByDir( SMESHDS_Mesh* mesh, const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); newNodes.push_back( newNode ); } + + if ( !myScales.empty() ) + { + if ( makeMediumNodes && myMediumScales.empty() ) + { + myMediumScales.resize( myScales.size() ); + double prevFactor = 1.; + for ( size_t i = 0; i < myScales.size(); ++i ) + { + myMediumScales[i] = 0.5 * ( prevFactor + myScales[i] ); + prevFactor = myScales[i]; + } + } + typedef std::vector::iterator ScaleIt; + ScaleIt scales[] = { myScales.begin(), myMediumScales.begin() }; + + size_t iSc = 0, nbScales = myScales.size() + myMediumScales.size(); + + gp_XYZ center = myBaseP; + std::list::iterator nIt = newNodes.begin(); + size_t iN = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps() && ( iN < nbScales ); ++nIt, ++iN ) + { + center += myDir.XYZ() * nextStep(); + + iSc += int( makeMediumNodes ); + ScaleIt& scale = scales[ iSc % 2 ]; + + gp_XYZ xyz = SMESH_NodeXYZ( *nIt ); + xyz = ( *scale * ( xyz - center )) + center; + mesh->MoveNode( *nIt, xyz.X(), xyz.Y(), xyz.Z() ); + + ++scale; + } + } return nbNodes; } @@ -5431,7 +5447,7 @@ makeNodesByDirAndSew( SMESHDS_Mesh* mesh, std::list & newNodes, const bool makeMediumNodes) { - gp_XYZ P1 = SMESH_TNodeXYZ( srcNode ); + gp_XYZ P1 = SMESH_NodeXYZ( srcNode ); int nbNodes = 0; for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps @@ -5439,13 +5455,14 @@ makeNodesByDirAndSew( SMESHDS_Mesh* mesh, P1 += myDir.XYZ() * nextStep(); // try to search in sequence of existing nodes - // if myNodes.Length()>0 we 'nave to use given sequence + // if myNodes.size()>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 ( myNodes.Length() > 0 ) + { + for ( int i = 1; i <= myNodes.Length(); i++ ) + { + SMESH_NodeXYZ P2 = myNodes.Value(i); if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) { node = myNodes.Value(i); @@ -5453,10 +5470,12 @@ makeNodesByDirAndSew( SMESHDS_Mesh* mesh, } } } - else { + else + { SMDS_NodeIteratorPtr itn = mesh->nodesIterator(); - while(itn->more()) { - SMESH_TNodeXYZ P2( itn->next() ); + while(itn->more()) + { + SMESH_NodeXYZ P2 = itn->next(); if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) { node = P2._node; @@ -5488,7 +5507,7 @@ makeNodesByNormal2D( SMESHDS_Mesh* mesh, { const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ); - gp_XYZ p = SMESH_TNodeXYZ( srcNode ); + gp_XYZ p = SMESH_NodeXYZ( srcNode ); // get normals to faces sharing srcNode vector< gp_XYZ > norms, baryCenters; @@ -5508,7 +5527,7 @@ makeNodesByNormal2D( SMESHDS_Mesh* mesh, gp_XYZ bc(0,0,0); int nbN = 0; for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN ) - bc += SMESH_TNodeXYZ( nIt->next() ); + bc += SMESH_NodeXYZ( nIt->next() ); baryCenters.push_back( bc / nbN ); } } @@ -5591,7 +5610,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElems[2], const int theFlags, const double theTolerance) { - ExtrusParam aParams( theStep, theNbSteps, theFlags, theTolerance ); + ExtrusParam aParams( theStep, theNbSteps, std::list(), 0, theFlags, theTolerance ); return ExtrusionSweep( theElems, aParams, newElemsMap ); } @@ -5606,22 +5625,22 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2], ExtrusParam& theParams, TTElemOfElemListMap& newElemsMap) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); + + setElemsFirst( theElemSets ); + myLastCreatedElems.reserve( theElemSets[0].size() * theParams.NbSteps() ); + myLastCreatedNodes.reserve( theElemSets[1].size() * theParams.NbSteps() ); // source elements for each generated one SMESH_SequenceOfElemPtr srcElems, srcNodes; + srcElems.reserve( theElemSets[0].size() ); + srcNodes.reserve( theElemSets[1].size() ); - SMESHDS_Mesh* aMesh = GetMeshDS(); - - setElemsFirst( theElemSets ); const int nbSteps = theParams.NbSteps(); - theParams.SetElementsToUse( theElemSets[0] ); + theParams.SetElementsToUse( theElemSets[0], theElemSets[1] ); - TNodeOfNodeListMap mapNewNodes; - //TNodeOfNodeVecMap mapNewNodes; + TNodeOfNodeListMap mapNewNodes; TElemOfVecOfNnlmiMap mapElemNewNodes; - //TElemOfVecOfMapNodesMap mapElemNewNodes; const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC) + @@ -5675,8 +5694,8 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2], list::iterator newNodesIt = listNewNodes.begin(); for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt ) { - myLastCreatedNodes.Append( *newNodesIt ); - srcNodes.Append( node ); + myLastCreatedNodes.push_back( *newNodesIt ); + srcNodes.push_back( node ); } } else @@ -5717,9 +5736,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], const gp_Pnt& theRefPoint, const bool theMakeGroups) { - MESSAGE("ExtrusionAlongTrack"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); int aNbE; std::list aPrms; @@ -5745,6 +5762,10 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], ASSERT( theTrack ); SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS(); + if ( !pSubMeshDS ) + return ExtrusionAlongTrack( theElements, theTrack->GetFather(), theN1, + theHasAngles, theAngles, theLinearVariation, + theHasRefPoint, theRefPoint, theMakeGroups ); aItE = pSubMeshDS->GetElements(); while ( aItE->more() ) { @@ -5774,14 +5795,13 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], return EXTR_BAD_STARTING_NODE; aItN = pSubMeshDS->GetNodes(); while ( aItN->more() ) { - const SMDS_MeshNode* pNode = aItN->next(); - const SMDS_EdgePosition* pEPos = - static_cast( pNode->GetPosition() ); + const SMDS_MeshNode* pNode = aItN->next(); + SMDS_EdgePositionPtr pEPos = pNode->GetPosition(); double aT = pEPos->GetUParameter(); aPrms.push_back( aT ); } //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); } else if( aS.ShapeType() == TopAbs_WIRE ) { list< SMESH_subMesh* > LSM; TopTools_SequenceOfShape Edges; @@ -5819,17 +5839,16 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], aItN = locMeshDS->GetNodes(); while ( aItN->more() ) { const SMDS_MeshNode* pNode = aItN->next(); - const SMDS_EdgePosition* pEPos = - static_cast( pNode->GetPosition() ); + SMDS_EdgePositionPtr pEPos = pNode->GetPosition(); double aT = pEPos->GetUParameter(); aPrms.push_back( aT ); } list LPP; //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); + makeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); LLPPs.push_back(LPP); UsedNums.Add(k); - // update startN for search following egde + // update startN for search following edge if( aN1->GetID() == startNid ) startNid = aN2->GetID(); else startNid = aN1->GetID(); break; @@ -5869,7 +5888,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], return EXTR_BAD_PATH_SHAPE; } - return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, theHasRefPoint, theRefPoint, theMakeGroups); } @@ -5889,8 +5908,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], const gp_Pnt& theRefPoint, const bool theMakeGroups) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); int aNbE; std::list aPrms; @@ -5943,7 +5961,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMDS_ElemIteratorPtr nIt; //check start node - if( !theTrack->GetMeshDS()->Contains(theN1) ) { + if( !theTrack->GetMeshDS()->Contains( theN1 )) { return EXTR_BAD_STARTING_NODE; } @@ -5999,21 +6017,19 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], return EXTR_PATH_NOT_EDGE; TopTools_SequenceOfShape Edges; - double x1,x2,y1,y2,z1,z2; list< list > LLPPs; int startNid = theN1->GetID(); - for(int i = 1; i < aNodesList.size(); i++) { - x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X(); - y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y(); - z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z(); - TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2)); + for ( size_t i = 1; i < aNodesList.size(); i++ ) + { + gp_Pnt p1 = SMESH_NodeXYZ( aNodesList[i-1] ); + gp_Pnt p2 = SMESH_NodeXYZ( aNodesList[i] ); + TopoDS_Edge e = BRepBuilderAPI_MakeEdge( p1, p2 ); list LPP; aPrms.clear(); - MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); + makeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); LLPPs.push_back(LPP); - if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID(); - else startNid = aNodesList[i-1]->GetID(); - + if ( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i ]->GetID(); + else startNid = aNodesList[i-1]->GetID(); } list< list >::iterator itLLPP = LLPPs.begin(); @@ -6033,8 +6049,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], 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( 0.5 * ( D1.XYZ() + D2.XYZ() )); PP1.SetTangent(Dnew); fullList.push_back(PP1); itPP++; @@ -6047,7 +6062,8 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], fullList.push_back(PP1); } // Sub-shape for the Pattern must be an Edge or Wire - else if( aS.ShapeType() == TopAbs_EDGE ) { + else if ( aS.ShapeType() == TopAbs_EDGE ) + { aTrackEdge = TopoDS::Edge( aS ); // the Edge must not be degenerated if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) @@ -6062,13 +6078,12 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], while ( aItN->more() ) { const SMDS_MeshNode* pNode = aItN->next(); if( pNode==aN1 || pNode==aN2 ) continue; - const SMDS_EdgePosition* pEPos = - static_cast( pNode->GetPosition() ); + SMDS_EdgePositionPtr pEPos = pNode->GetPosition(); double aT = pEPos->GetUParameter(); aPrms.push_back( aT ); } //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); } else if( aS.ShapeType() == TopAbs_WIRE ) { list< SMESH_subMesh* > LSM; @@ -6119,18 +6134,17 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], aPrms.clear(); aItN = locMeshDS->GetNodes(); while ( aItN->more() ) { - const SMDS_MeshNode* pNode = aItN->next(); - const SMDS_EdgePosition* pEPos = - static_cast( pNode->GetPosition() ); + const SMDS_MeshNode* pNode = aItN->next(); + SMDS_EdgePositionPtr pEPos = pNode->GetPosition(); double aT = pEPos->GetUParameter(); aPrms.push_back( aT ); } list LPP; //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP); + makeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP); LLPPs.push_back(LPP); UsedNums.Add(k); - // update startN for search following egde + // update startN for search following edge if ( aN1isOK ) aVprev = aV2; else aVprev = aV1; break; @@ -6148,7 +6162,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_MeshEditor_PathPoint PP2 = currList.front(); gp_Dir D1 = PP1.Tangent(); gp_Dir D2 = PP2.Tangent(); - gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 ); + gp_Dir Dnew( D1.XYZ() + D2.XYZ() ); PP1.SetTangent(Dnew); fullList.push_back(PP1); fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() ); @@ -6163,17 +6177,17 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], return EXTR_BAD_PATH_SHAPE; } - return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, theHasRefPoint, theRefPoint, theMakeGroups); } //======================================================================= -//function : MakeEdgePathPoints -//purpose : auxilary for ExtrusionAlongTrack +//function : makeEdgePathPoints +//purpose : auxiliary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, +SMESH_MeshEditor::makeEdgePathPoints(std::list& aPrms, const TopoDS_Edge& aTrackEdge, bool FirstIsStart, list& LPP) @@ -6213,7 +6227,7 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, aL2 = aVec.SquareMagnitude(); if ( aL2 < aTolVec2 ) return EXTR_CANT_GET_TANGENT; - gp_Dir aTgt( aVec ); + gp_Dir aTgt( FirstIsStart ? aVec : -aVec ); aPP.SetPnt( aP3D ); aPP.SetTangent( aTgt ); aPP.SetParameter( aT ); @@ -6224,11 +6238,11 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, //======================================================================= -//function : MakeExtrElements -//purpose : auxilary for ExtrusionAlongTrack +//function : makeExtrElements +//purpose : auxiliary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2], +SMESH_MeshEditor::makeExtrElements(TIDSortedElemSet theElemSets[2], list& fullList, const bool theHasAngles, list& theAngles, @@ -6238,9 +6252,11 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets const bool theMakeGroups) { const int aNbTP = fullList.size(); + // Angles if( theHasAngles && !theAngles.empty() && theLinearVariation ) - LinearAngleVariation(aNbTP-1, theAngles); + linearAngleVariation(aNbTP-1, theAngles); + // fill vector of path points with angles vector aPPs; list::iterator itPP = fullList.begin(); @@ -6270,14 +6286,14 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets { TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; itElem = theElements.begin(); - for ( ; itElem != theElements.end(); itElem++ ) { + for ( ; itElem != theElements.end(); itElem++ ) + { const SMDS_MeshElement* elem = *itElem; - - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { const SMDS_MeshElement* node = itN->next(); if ( newNodes.insert( node ).second ) - aGC += SMESH_TNodeXYZ( node ); + aGC += SMESH_NodeXYZ( node ); } } } @@ -6287,19 +6303,15 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets // 4. Processing the elements SMESHDS_Mesh* aMesh = GetMeshDS(); + list emptyList; setElemsFirst( theElemSets ); for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) { TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; - for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { - // check element type + for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) + { const SMDS_MeshElement* elem = *itElem; - if ( !elem ) - continue; - // SMDSAbs_ElementType aTypeE = elem->GetType(); - // if ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) - // continue; vector & newNodesItVec = mapElemNewNodes[ elem ]; newNodesItVec.reserve( elem->NbNodes() ); @@ -6311,13 +6323,11 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets { ++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; - + const SMDS_MeshNode* node = cast2Node( itN->next() ); + TNodeOfNodeListMap::iterator nIt = mapNewNodes.insert( make_pair( node, emptyList )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) + { // make new nodes Standard_Real aAngle1x, aAngleT1T0, aTolAng; gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; @@ -6327,12 +6337,11 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets aTolAng=1.e-4; aV0x = aV0; - aPN0 = SMESH_TNodeXYZ( node ); + aPN0 = SMESH_NodeXYZ( node ); const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; aP0x = aPP0.Pnt(); aDT0x= aPP0.Tangent(); - //cout<<"j = 0 PP: Pnt("< aTolAng) { + if (fabs(aAngleT1T0) > aTolAng) + { aDT1T0=aDT1x^aDT0x; anAxT1T0.SetLocation( aV1x ); anAxT1T0.SetDirection( aDT1T0 ); @@ -6370,20 +6380,18 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets } // make new node - //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node)); - if( 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 ); + gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() ); + const SMDS_MeshNode* newNode = aMesh->AddNode( midP.X(), midP.Y(), midP.Z() ); + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( node ); listNewNodes.push_back( newNode ); } const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( node ); listNewNodes.push_back( newNode ); aPN0 = aPN1; @@ -6392,42 +6400,40 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets aDT0x = aDT1x; } } - - else { + else if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) + { // 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]); - } + list< const SMDS_MeshNode* > & listNewNodes = nIt->second; + if ((int) 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.push_back( node ); + myLastCreatedNodes.push_back(newN); + aNodes[2*i] = newN; + aNodes[2*i+1] = N; + P = gp_XYZ(N->X(),N->Y(),N->Z()); + } + listNewNodes.clear(); + for(i=0; i<2*(aNbTP-1); i++) { + listNewNodes.push_back(aNodes[i]); } } } newNodesItVec.push_back( nIt ); } + // make new elements - //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], - // newNodesItVec[0]->second.size(), myLastCreatedElems ); sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } } @@ -6442,25 +6448,24 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets //======================================================================= -//function : LinearAngleVariation -//purpose : auxilary for ExtrusionAlongTrack +//function : linearAngleVariation +//purpose : spread values over nbSteps //======================================================================= -void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, + +void SMESH_MeshEditor::linearAngleVariation(const int nbSteps, list& Angles) { int nbAngles = Angles.size(); - if( nbSteps > nbAngles ) { + if( nbSteps > nbAngles && nbAngles > 0 ) + { vector theAngles(nbAngles); - list::iterator it = Angles.begin(); - int i = -1; - for(; it!=Angles.end(); it++) { - i++; - theAngles[i] = (*it); - } + theAngles.assign( Angles.begin(), Angles.end() ); + list res; double rAn2St = double( nbAngles ) / double( nbSteps ); double angPrev = 0, angle; - for ( int iSt = 0; iSt < nbSteps; ++iSt ) { + for ( int iSt = 0; iSt < nbSteps; ++iSt ) + { double angCur = rAn2St * ( iSt+1 ); double angCurFloor = floor( angCur ); double angPrevFloor = floor( angPrev ); @@ -6482,10 +6487,7 @@ void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, res.push_back(angle); angPrev = angCur; } - Angles.clear(); - it = res.begin(); - for(; it!=res.end(); it++) - Angles.push_back( *it ); + Angles.swap( res ); } } @@ -6509,52 +6511,46 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, const bool theMakeGroups, SMESH_Mesh* theTargetMesh) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); + myLastCreatedElems.reserve( theElems.size() ); bool needReverse = false; string groupPostfix; switch ( theTrsf.Form() ) { case gp_PntMirror: - MESSAGE("gp_PntMirror"); needReverse = true; groupPostfix = "mirrored"; break; case gp_Ax1Mirror: - MESSAGE("gp_Ax1Mirror"); groupPostfix = "mirrored"; break; case gp_Ax2Mirror: - MESSAGE("gp_Ax2Mirror"); needReverse = true; groupPostfix = "mirrored"; break; case gp_Rotation: - MESSAGE("gp_Rotation"); groupPostfix = "rotated"; break; case gp_Translation: - MESSAGE("gp_Translation"); groupPostfix = "translated"; break; case gp_Scale: - MESSAGE("gp_Scale"); groupPostfix = "scaled"; break; case gp_CompoundTrsf: // different scale by axis - MESSAGE("gp_CompoundTrsf"); groupPostfix = "scaled"; break; default: - MESSAGE("default"); needReverse = false; 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; @@ -6586,196 +6582,116 @@ 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.push_back(newNode); + srcNodes.push_back( node ); + } + else if ( theCopy ) { + const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( 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; if ( !elem ) continue; SMDSAbs_GeometryType geomType = elem->GetGeomType(); - int nbNodes = elem->NbNodes(); + size_t nbNodes = elem->NbNodes(); if ( geomType == SMDSGeom_NONE ) continue; // node - switch ( geomType ) { + nodes.resize( nbNodes ); - case SMDSGeom_POLYGON: // ---------------------- polygon + if ( geomType == SMDSGeom_POLYHEDRA ) // ------------------ polyhedral volume + { + const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( 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; + size_t 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 @@ -6783,27 +6699,24 @@ 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.push_back( 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.swap( editor->myLastCreatedElems ); + PGroupIDs newGroupIDs; if ( ( theMakeGroups && theCopy ) || @@ -6813,51 +6726,147 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, return newGroupIDs; } -//======================================================================= +//================================================================================ /*! - * \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 targetMesh - mesh to create groups in - * \param topPresent - is there "top" elements that are created by sweeping + * \brief Make an offset mesh from a source 2D mesh + * \param [in] theElements - source faces + * \param [in] theValue - offset value + * \param [out] theTgtMesh - a mesh to add offset elements to + * \param [in] theMakeGroups - to generate groups + * \return PGroupIDs - IDs of created groups */ -//======================================================================= +//================================================================================ -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, - const SMESH_SequenceOfElemPtr& elemGens, - const std::string& postfix, - SMESH_Mesh* targetMesh, - const bool topPresent) +SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElements, + const double theValue, + SMESH_Mesh* theTgtMesh, + const bool theMakeGroups, + const bool theCopyElements, + const bool theFixSelfIntersection) { - PGroupIDs newGroupIDs( new list ); - SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh(); + SMESHDS_Mesh* meshDS = GetMeshDS(); + SMESHDS_Mesh* tgtMeshDS = theTgtMesh->GetMeshDS(); + SMESH_MeshEditor tgtEditor( theTgtMesh ); - // Sort existing groups by types and collect their names + SMDS_ElemIteratorPtr eIt; + if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face ); + else eIt = SMESHUtils::elemSetIterator( theElements ); - // 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; + SMESH_MeshAlgos::TEPairVec new2OldFaces; + SMESH_MeshAlgos::TNPairVec new2OldNodes; + std::unique_ptr< SMDS_Mesh > offsetMesh + ( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue, + theFixSelfIntersection, + new2OldFaces, new2OldNodes )); + if ( offsetMesh->NbElements() == 0 ) + return PGroupIDs(); // MakeOffset() failed - SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups(); - if ( !groupIt->more() ) return newGroupIDs; - int newGroupID = mesh->GetGroupIds().back()+1; - while ( groupIt->more() ) + if ( theTgtMesh == myMesh && !theCopyElements ) { - SMESH_Group * group = groupIt->next(); - if ( !group ) continue; - SMESHDS_GroupBase* groupDS = group->GetGroupDS(); - if ( !groupDS || groupDS->IsEmpty() ) continue; - groupNames.insert ( group->GetName() ); + // clear the source elements + if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face ); + else eIt = SMESHUtils::elemSetIterator( theElements ); + while ( eIt->more() ) + meshDS->RemoveFreeElement( eIt->next(), 0 ); + } + + // offsetMesh->Modified(); + // offsetMesh->CompactMesh(); // make IDs start from 1 + + // source elements for each generated one + SMESH_SequenceOfElemPtr srcElems, srcNodes; + srcElems.reserve( new2OldFaces.size() ); + srcNodes.reserve( new2OldNodes.size() ); + + ClearLastCreated(); + myLastCreatedElems.reserve( new2OldFaces.size() ); + myLastCreatedNodes.reserve( new2OldNodes.size() ); + + // copy offsetMesh to theTgtMesh + + int idShift = meshDS->MaxNodeID(); + for ( size_t i = 0; i < new2OldNodes.size(); ++i ) + if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first ) + { + if ( n->NbInverseElements() > 0 ) + { + const SMDS_MeshNode* n2 = + tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() ); + myLastCreatedNodes.push_back( n2 ); + srcNodes.push_back( new2OldNodes[ i ].second ); + } + } + + ElemFeatures elemType; + for ( size_t i = 0; i < new2OldFaces.size(); ++i ) + if ( const SMDS_MeshElement* f = new2OldFaces[ i ].first ) + { + elemType.Init( f ); + elemType.myNodes.clear(); + for ( SMDS_NodeIteratorPtr nIt = f->nodeIterator(); nIt->more(); ) + { + const SMDS_MeshNode* n2 = nIt->next(); + elemType.myNodes.push_back( tgtMeshDS->FindNode( idShift + n2->GetID() )); + } + tgtEditor.AddElement( elemType.myNodes, elemType ); + srcElems.push_back( new2OldFaces[ i ].second ); + } + + myLastCreatedElems.swap( tgtEditor.myLastCreatedElems ); + + PGroupIDs newGroupIDs; + if ( theMakeGroups ) + newGroupIDs = generateGroups( srcNodes, srcElems, "offset", theTgtMesh, false ); + + return newGroupIDs; +} + +//======================================================================= +/*! + * \brief Create groups of elements made during transformation + * \param nodeGens - nodes making corresponding myLastCreatedNodes + * \param elemGens - elements making corresponding myLastCreatedElems + * \param postfix - to push_back to names of new groups + * \param targetMesh - mesh to create groups in + * \param topPresent - is there are "top" elements that are created by sweeping + */ +//======================================================================= + +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, + const SMESH_SequenceOfElemPtr& elemGens, + const std::string& postfix, + 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 + + // 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; + + SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups(); + if ( !groupIt->more() ) return newGroupIDs; + + int newGroupID = mesh->GetGroupIds().back()+1; + while ( groupIt->more() ) + { + SMESH_Group * group = groupIt->next(); + if ( !group ) continue; + SMESHDS_GroupBase* groupDS = group->GetGroupDS(); + if ( !groupDS || groupDS->IsEmpty() ) continue; + groupNames.insert ( group->GetName() ); groupDS->SetStoreName( group->GetName() ); const SMDSAbs_ElementType type = groupDS->GetType(); SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); @@ -6873,30 +6882,30 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, { const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems; - if ( gens.Length() != elems.Length() ) + if ( gens.size() != elems.size() ) throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args"); // loop on created elements - for (int iElem = 1; iElem <= elems.Length(); ++iElem ) + for (size_t iElem = 0; iElem < elems.size(); ++iElem ) { - const SMDS_MeshElement* sourceElem = gens( iElem ); + const SMDS_MeshElement* sourceElem = gens[ iElem ]; if ( !sourceElem ) { MESSAGE("generateGroups(): NULL source element"); continue; } list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ]; if ( groupsOldNew.empty() ) { // no groups of this type at all - while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) + while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem ) ++iElem; // skip all elements made by sourceElem continue; } // collect all elements made by the iElem-th sourceElem resultElems.clear(); - if ( const SMDS_MeshElement* resElem = elems( iElem )) + if ( const SMDS_MeshElement* resElem = elems[ iElem ]) if ( resElem != sourceElem ) resultElems.push_back( resElem ); - while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) - if ( const SMDS_MeshElement* resElem = elems( ++iElem )) + while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem ) + if ( const SMDS_MeshElement* resElem = elems[ ++iElem ]) if ( resElem != sourceElem ) resultElems.push_back( resElem ); @@ -6936,7 +6945,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, { SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup(); newTopGroup.Add( topElem ); - } + } } } } // loop on created elements @@ -7007,32 +7016,71 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, //================================================================================ /*! - * \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(); + ClearLastCreated(); - if ( theNodes.empty() ) - { // get all nodes in the mesh - SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true); - while ( nIt->more() ) - theNodes.insert( theNodes.end(),nIt->next()); + 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(); + 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 ); } //======================================================================= //function : SimplifyFace -//purpose : +//purpose : split a chain of nodes into several closed chains //======================================================================= int SMESH_MeshEditor::SimplifyFace (const vector& faceNodes, @@ -7040,78 +7088,52 @@ int SMESH_MeshEditor::SimplifyFace (const vector& faceNod vector& quantities) const { int nbNodes = faceNodes.size(); - - if (nbNodes < 3) + while ( faceNodes[ 0 ] == faceNodes[ nbNodes-1 ] && nbNodes > 2 ) + --nbNodes; + if ( nbNodes < 3 ) return 0; + size_t prevNbQuant = quantities.size(); - set nodeSet; - - // get simple seq of nodes - //const SMDS_MeshNode* simpleNodes[ nbNodes ]; - vector simpleNodes( nbNodes ); - int iSimple = 0, nbUnique = 0; - - simpleNodes[iSimple++] = faceNodes[0]; - nbUnique++; - for (int iCur = 1; iCur < nbNodes; iCur++) { - if (faceNodes[iCur] != simpleNodes[iSimple - 1]) { - simpleNodes[iSimple++] = faceNodes[iCur]; - if (nodeSet.insert( faceNodes[iCur] ).second) - nbUnique++; - } - } - int nbSimple = iSimple; - if (simpleNodes[nbSimple - 1] == simpleNodes[0]) { - nbSimple--; - iSimple--; - } - - if (nbUnique < 3) - return 0; + vector< const SMDS_MeshNode* > simpleNodes; simpleNodes.reserve( nbNodes ); + map< const SMDS_MeshNode*, int > nodeIndices; // indices within simpleNodes + map< const SMDS_MeshNode*, int >::iterator nInd; - // separate loops - int nbNew = 0; - bool foundLoop = (nbSimple > nbUnique); - while (foundLoop) { - foundLoop = false; - set loopSet; - for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) { - const SMDS_MeshNode* n = simpleNodes[iSimple]; - if (!loopSet.insert( n ).second) { - foundLoop = true; - - // separate loop - int iC = 0, curLast = iSimple; - for (; iC < curLast; iC++) { - if (simpleNodes[iC] == n) break; - } - int loopLen = curLast - iC; - if (loopLen > 2) { - // create sub-element - nbNew++; - quantities.push_back(loopLen); - for (; iC < curLast; iC++) { - poly_nodes.push_back(simpleNodes[iC]); - } - } - // shift the rest nodes (place from the first loop position) - for (iC = curLast + 1; iC < nbSimple; iC++) { - simpleNodes[iC - loopLen] = simpleNodes[iC]; + nodeIndices.insert( make_pair( faceNodes[0], 0 )); + simpleNodes.push_back( faceNodes[0] ); + for ( int iCur = 1; iCur < nbNodes; iCur++ ) + { + if ( faceNodes[ iCur ] != simpleNodes.back() ) + { + int index = simpleNodes.size(); + nInd = nodeIndices.insert( make_pair( faceNodes[ iCur ], index )).first; + int prevIndex = nInd->second; + if ( prevIndex < index ) + { + // a sub-loop found + int loopLen = index - prevIndex; + if ( loopLen > 2 ) + { + // store the sub-loop + quantities.push_back( loopLen ); + for ( int i = prevIndex; i < index; i++ ) + poly_nodes.push_back( simpleNodes[ i ]); } - nbSimple -= loopLen; - iSimple -= loopLen; + simpleNodes.resize( prevIndex+1 ); + } + else + { + simpleNodes.push_back( faceNodes[ iCur ]); } - } // for (iSimple = 0; iSimple < nbSimple; iSimple++) - } // while (foundLoop) + } + } - if (iSimple > 2) { - nbNew++; - quantities.push_back(iSimple); - for (int i = 0; i < iSimple; i++) - poly_nodes.push_back(simpleNodes[i]); + if ( simpleNodes.size() > 2 ) + { + quantities.push_back( simpleNodes.size() ); + poly_nodes.insert ( poly_nodes.end(), simpleNodes.begin(), simpleNodes.end() ); } - return nbNew; + return quantities.size() - prevNbQuant; } //======================================================================= @@ -7120,41 +7142,30 @@ int SMESH_MeshEditor::SimplifyFace (const vector& faceNod // in all elements. //======================================================================= -void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) +void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes, + const bool theAvoidMakingHoles) { - MESSAGE("MergeNodes"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); - SMESHDS_Mesh* aMesh = GetMeshDS(); + SMESHDS_Mesh* mesh = GetMeshDS(); TNodeNodeMap nodeNodeMap; // node to replace - new node set elems; // all elements with changed nodes list< int > rmElemIds, rmNodeIds; + vector< ElemFeatures > newElemDefs; // 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()); - 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 ); - } - + nodeNodeMap.insert( make_pair( nToRemove, nToKeep )); SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); while ( invElemIt->more() ) { const SMDS_MeshElement* elem = invElemIt->next(); @@ -7162,640 +7173,624 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } } } + + // Apply recursive replacements (BUG 0020185) + TNodeNodeMap::iterator nnIt = nodeNodeMap.begin(); + for ( ; nnIt != nodeNodeMap.end(); ++nnIt ) + { + const SMDS_MeshNode* nToKeep = nnIt->second; + TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( nToKeep ); + while ( nnIt_i != nodeNodeMap.end() && nnIt_i->second != nnIt->second ) + { + nToKeep = nnIt_i->second; + nnIt->second = nToKeep; + nnIt_i = nodeNodeMap.find( nToKeep ); + } + } + + if ( theAvoidMakingHoles ) + { + // find elements whose topology changes + + vector pbElems; + set::iterator eIt = elems.begin(); + for ( ; eIt != elems.end(); ++eIt ) + { + const SMDS_MeshElement* elem = *eIt; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); + TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); + if ( nnIt != nodeNodeMap.end() && elem->GetNodeIndex( nnIt->second ) >= 0 ) + { + // several nodes of elem stick + pbElems.push_back( elem ); + break; + } + } + } + // exclude from merge nodes causing spoiling element + for ( size_t iLoop = 0; iLoop < pbElems.size(); ++iLoop ) // avoid infinite cycle + { + bool nodesExcluded = false; + for ( size_t i = 0; i < pbElems.size(); ++i ) + { + size_t prevNbMergeNodes = nodeNodeMap.size(); + if ( !applyMerge( pbElems[i], newElemDefs, nodeNodeMap, /*noHoles=*/true ) && + prevNbMergeNodes < nodeNodeMap.size() ) + nodesExcluded = true; + } + if ( !nodesExcluded ) + break; + } + } + + for ( nnIt = nodeNodeMap.begin(); nnIt != nodeNodeMap.end(); ++nnIt ) + { + const SMDS_MeshNode* nToRemove = nnIt->first; + const SMDS_MeshNode* nToKeep = nnIt->second; + if ( nToRemove != nToKeep ) + { + rmNodeIds.push_back( nToRemove->GetID() ); + AddToSameGroups( nToKeep, nToRemove, mesh ); + // set _alwaysComputed to a sub-mesh of VERTEX to enable further mesh computing + // w/o creating node in place of merged ones. + SMDS_PositionPtr pos = nToRemove->GetPosition(); + if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() )) + sm->SetIsAlwaysComputed( true ); + } + } + // Change element nodes or remove an element set::iterator eIt = elems.begin(); - for ( ; eIt != elems.end(); eIt++ ) { + for ( ; eIt != elems.end(); eIt++ ) + { const SMDS_MeshElement* elem = *eIt; - //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID()); - int nbNodes = elem->NbNodes(); - int aShapeId = FindShape( elem ); + SMESHDS_SubMesh* sm = mesh->MeshElements( elem->getshapeId() ); - set nodeSet; - vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes ); - int iUnique = 0, iCur = 0, nbRepl = 0; - vector iRepl( nbNodes ); + bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false ); + if ( !keepElem ) + rmElemIds.push_back( elem->GetID() ); - // get new seq of nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - 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 + for ( size_t i = 0; i < newElemDefs.size(); ++i ) + { + if ( i > 0 || !mesh->ChangeElementNodes( elem, + & newElemDefs[i].myNodes[0], + newElemDefs[i].myNodes.size() )) + { + if ( i == 0 ) { - bool stopRecur = false; - set nodesRecur; - nodesRecur.insert(n); - while (!stopRecur) { - TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n ); - if ( nnIt_i != nodeNodeMap.end() ) { // n sticks - n = (*nnIt_i).second; - if (!nodesRecur.insert(n).second) { - // error: recursive dependancy - stopRecur = true; - } - } - else - stopRecur = true; - } + newElemDefs[i].SetID( elem->GetID() ); + mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); + if ( !keepElem ) rmElemIds.pop_back(); + } + else + { + newElemDefs[i].SetID( -1 ); } - // BUG 0020185: end + SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] ); + if ( sm && newElem ) + sm->AddElement( newElem ); + if ( elem != newElem ) + ReplaceElemInGroups( elem, newElem, mesh ); } - curNodes[ iCur ] = n; - bool isUnique = nodeSet.insert( n ).second; - if ( isUnique ) - uniqueNodes[ iUnique++ ] = n; - else - iRepl[ nbRepl++ ] = iCur; - iCur++; } + } - // Analyse element topology after replacement + // Remove bad elements, then equal nodes (order important) + Remove( rmElemIds, /*isNodes=*/false ); + Remove( rmNodeIds, /*isNodes=*/true ); - 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()) { + return; +} - if (elem->GetType() == SMDSAbs_Face) { - // Polygon - vector face_nodes (nbNodes); - int inode = 0; - for (; inode < nbNodes; inode++) { - face_nodes[inode] = curNodes[inode]; - } +//======================================================================= +//function : applyMerge +//purpose : Compute new connectivity of an element after merging nodes +// \param [in] elems - the element +// \param [out] newElemDefs - definition(s) of result element(s) +// \param [inout] nodeNodeMap - nodes to merge +// \param [in] avoidMakingHoles - if true and and the element becomes invalid +// after merging (but not degenerated), removes nodes causing +// the invalidity from \a nodeNodeMap. +// \return bool - true if the element should be removed +//======================================================================= - 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]; - } - SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); - myLastCreatedElems.Append(newElem); - if (aShapeId) - aMesh->SetMeshElementOnShape(newElem, aShapeId); - } +bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem, + vector< ElemFeatures >& newElemDefs, + TNodeNodeMap& nodeNodeMap, + const bool avoidMakingHoles ) +{ + bool toRemove = false; // to remove elem + int nbResElems = 1; // nb new elements - 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()); - } + newElemDefs.resize(nbResElems); + newElemDefs[0].Init( elem ); + newElemDefs[0].myNodes.clear(); - } - else if (elem->GetType() == SMDSAbs_Volume) { - // Polyhedral volume - if (nbUniqueNodes < 4) { - rmElemIds.push_back(elem->GetID()); - } - else { - // each face has to be analyzed in order to check volume validity - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( elem ); - if (aPolyedre) { - int nbFaces = aPolyedre->NbFaces(); - - vector poly_nodes; - vector quantities; - - for (int iface = 1; iface <= nbFaces; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - vector faceNodes (nbFaceNodes); - - for (int inode = 1; inode <= nbFaceNodes; inode++) { - const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); - if (nnIt != nodeNodeMap.end()) { // faceNode sticks - faceNode = (*nnIt).second; - } - faceNodes[inode - 1] = faceNode; - } + set nodeSet; + vector< const SMDS_MeshNode*> curNodes; + vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes; + vector iRepl; - SimplifyFace(faceNodes, poly_nodes, quantities); - } + const int nbNodes = elem->NbNodes(); + SMDSAbs_EntityType entity = elem->GetEntityType(); - if (quantities.size() > 3) { - // to be done: remove coincident faces - } + curNodes.resize( nbNodes ); + uniqueNodes.resize( nbNodes ); + iRepl.resize( nbNodes ); + int iUnique = 0, iCur = 0, nbRepl = 0; - if (quantities.size() > 3) - { - MESSAGE("ChangeElementNodes MergeNodes Polyhedron"); - //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - const SMDS_MeshElement* newElem = 0; - newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - rmElemIds.push_back(elem->GetID()); - } - } - else { - rmElemIds.push_back(elem->GetID()); - } - } - } - else { - } + // Get new seq of nodes - continue; - } // poly element - - // Regular elements - // TODO not all the possible cases are solved. Find something more generic? - switch ( nbNodes ) { - case 2: ///////////////////////////////////// EDGE - isOk = false; break; - case 3: ///////////////////////////////////// TRIANGLE - isOk = false; break; - case 4: - if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON - isOk = false; - else { //////////////////////////////////// QUADRANGLE - if ( nbUniqueNodes < 3 ) - isOk = false; - else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 ) - isOk = false; // opposite nodes stick - //MESSAGE("isOk " << isOk); - } - break; - case 6: ///////////////////////////////////// PENTAHEDRON - if ( nbUniqueNodes == 4 ) { - // ---------------------------------> tetrahedron - if (nbRepl == 3 && - iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) { - // all top nodes stick: reverse a bottom - uniqueNodes[ 0 ] = curNodes [ 1 ]; - uniqueNodes[ 1 ] = curNodes [ 0 ]; - } - else if (nbRepl == 3 && - iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) { - // all bottom nodes stick: set a top before - uniqueNodes[ 3 ] = uniqueNodes [ 0 ]; - uniqueNodes[ 0 ] = curNodes [ 3 ]; - uniqueNodes[ 1 ] = curNodes [ 4 ]; - uniqueNodes[ 2 ] = curNodes [ 5 ]; - } - else if (nbRepl == 4 && - iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) { - // a lateral face turns into a line: reverse a bottom - uniqueNodes[ 0 ] = curNodes [ 1 ]; - uniqueNodes[ 1 ] = curNodes [ 0 ]; - } - else - isOk = false; - } - else if ( nbUniqueNodes == 5 ) { - // PENTAHEDRON --------------------> 2 tetrahedrons - if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) { - // a bottom node sticks with a linked top one - // 1. - SMDS_MeshElement* newElem = - aMesh->AddVolume(curNodes[ 3 ], - curNodes[ 4 ], - curNodes[ 5 ], - curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]); - myLastCreatedElems.Append(newElem); - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - // 2. : reverse a bottom - uniqueNodes[ 0 ] = curNodes [ 1 ]; - uniqueNodes[ 1 ] = curNodes [ 0 ]; - nbUniqueNodes = 4; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); + + TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); + if ( nnIt != nodeNodeMap.end() ) { + n = (*nnIt).second; + } + curNodes[ iCur ] = n; + bool isUnique = nodeSet.insert( n ).second; + if ( isUnique ) + uniqueNodes[ iUnique++ ] = n; + else + iRepl[ nbRepl++ ] = iCur; + iCur++; + } + + // Analyse element topology after replacement + + int nbUniqueNodes = nodeSet.size(); + if ( nbNodes != nbUniqueNodes ) // some nodes stick + { + toRemove = true; + nbResElems = 0; + + if ( newElemDefs[0].myIsQuad && newElemDefs[0].myType == SMDSAbs_Face && nbNodes > 6 ) + { + // if corner nodes stick, remove medium nodes between them from uniqueNodes + int nbCorners = nbNodes / 2; + for ( int iCur = 0; iCur < nbCorners; ++iCur ) + { + int iNext = ( iCur + 1 ) % nbCorners; + if ( curNodes[ iCur ] == curNodes[ iNext ] ) // corners stick + { + int iMedium = iCur + nbCorners; + vector< const SMDS_MeshNode* >::iterator i = + std::find( uniqueNodes.begin() + nbCorners - nbRepl, + uniqueNodes.end(), + curNodes[ iMedium ]); + if ( i != uniqueNodes.end() ) + { + --nbUniqueNodes; + for ( ; i+1 != uniqueNodes.end(); ++i ) + *i = *(i+1); } - else - isOk = false; } - else - isOk = false; - break; - case 8: { - if(elem->IsQuadratic()) { // Quadratic quadrangle - // 1 5 2 - // +---+---+ - // | | - // | | - // 4+ +6 - // | | - // | | - // +---+---+ - // 0 7 3 - isOk = false; - if(nbRepl==2) { - MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]); - } - if(nbRepl==3) { - MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]); - nbUniqueNodes = 6; - if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[5]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[6]; - isOk = true; - } - if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[1]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[5]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[0]; - isOk = true; - } - if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[1]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[2]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[3]; - isOk = true; + } + } + + switch ( entity ) + { + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: // Polygon + { + ElemFeatures* elemType = & newElemDefs[0]; + 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; + nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities ); + newElemDefs.resize( nbResElems ); + for ( int inode = 0, iface = 0; iface < nbResElems; iface++ ) + { + ElemFeatures* elemType = & newElemDefs[iface]; + if ( iface ) elemType->Init( elem ); + + vector& face_nodes = elemType->myNodes; + 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 ); + } + elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 )); + } + nbUniqueNodes = newElemDefs[0].myNodes.size(); + break; + } // Polygon + + case SMDSEntity_Polyhedra: // Polyhedral volume + { + if ( nbUniqueNodes >= 4 ) + { + // each face has to be analyzed in order to check volume validity + if ( const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem )) + { + int nbFaces = aPolyedre->NbFaces(); + + vector& poly_nodes = newElemDefs[0].myNodes; + vector & quantities = newElemDefs[0].myPolyhedQuantities; + vector faceNodes; + poly_nodes.clear(); + quantities.clear(); + + for (int iface = 1; iface <= nbFaces; iface++) + { + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + faceNodes.resize( nbFaceNodes ); + for (int inode = 1; inode <= nbFaceNodes; inode++) + { + const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); + TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); + if ( nnIt != nodeNodeMap.end() ) // faceNode sticks + faceNode = (*nnIt).second; + faceNodes[inode - 1] = faceNode; } + SimplifyFace(faceNodes, poly_nodes, quantities); } - if(nbRepl==4) { - MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]); - } - if(nbRepl==5) { - MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]); - } - break; - } - //////////////////////////////////// HEXAHEDRON - isOk = false; - SMDS_VolumeTool hexa (elem); - hexa.SetExternalNormal(); - if ( nbUniqueNodes == 4 && nbRepl == 4 ) { - //////////////////////// HEX ---> 1 tetrahedron - for ( int iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { - // one face turns into a point ... - int iOppFace = hexa.GetOppFaceIndex( iFace ); - ind = hexa.GetFaceNodesIndices( iOppFace ); - int nbStick = 0; - for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) { - if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) - nbStick++; - } - if ( nbStick == 1 ) { - // ... and the opposite one - into a triangle. - // set a top node - ind = hexa.GetFaceNodesIndices( iFace ); - uniqueNodes[ 3 ] = curNodes[ind[ 0 ]]; - isOk = true; - } - break; - } + + if ( quantities.size() > 3 ) + { + // TODO: remove coincident faces + nbResElems = 1; + nbUniqueNodes = newElemDefs[0].myNodes.size(); } } - else if ( nbUniqueNodes == 6 && nbRepl == 2 ) { - //////////////////////// HEX ---> 1 prism - int nbTria = 0, iTria[3]; - const int *ind; // indices of face nodes - // look for triangular faces - for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) { - ind = hexa.GetFaceNodesIndices( iFace ); - TIDSortedNodeSet faceNodes; - for ( iCur = 0; iCur < 4; iCur++ ) - faceNodes.insert( curNodes[ind[iCur]] ); - if ( faceNodes.size() == 3 ) - iTria[ nbTria++ ] = iFace; - } - // check if triangles are opposite - if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] )) - { - isOk = true; - // set nodes of the bottom triangle - ind = hexa.GetFaceNodesIndices( iTria[ 0 ]); - vector indB; - for ( iCur = 0; iCur < 4; iCur++ ) - if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1]) - indB.push_back( ind[iCur] ); - if ( !hexa.IsForward() ) - std::swap( indB[0], indB[2] ); - for ( iCur = 0; iCur < 3; iCur++ ) - uniqueNodes[ iCur ] = curNodes[indB[iCur]]; - // set nodes of the top triangle - const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]); - for ( iCur = 0; iCur < 3; ++iCur ) - for ( int j = 0; j < 4; ++j ) - if ( hexa.IsLinked( indB[ iCur ], indT[ j ] )) - { - uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]]; - break; - } - } - break; - } - else if (nbUniqueNodes == 5 && nbRepl == 4 ) { - //////////////////// HEXAHEDRON ---> 2 tetrahedrons - for ( int iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { - // one face turns into a point ... - int iOppFace = hexa.GetOppFaceIndex( iFace ); - ind = hexa.GetFaceNodesIndices( iOppFace ); - int nbStick = 0; - iUnique = 2; // reverse a tetrahedron 1 bottom - for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) { - if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) - nbStick++; - else if ( iUnique >= 0 ) - uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]]; - } - if ( nbStick == 0 ) { - // ... and the opposite one is a quadrangle - // set a top node - const int* indTop = hexa.GetFaceNodesIndices( iFace ); - uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]]; - nbUniqueNodes = 4; - // tetrahedron 2 - SMDS_MeshElement* newElem = - aMesh->AddVolume(curNodes[ind[ 0 ]], - curNodes[ind[ 3 ]], - curNodes[ind[ 2 ]], - curNodes[indTop[ 0 ]]); - myLastCreatedElems.Append(newElem); - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - isOk = true; - } - break; - } - } + } + } + break; + + // Regular elements + // TODO not all the possible cases are solved. Find something more generic? + case SMDSEntity_Edge: //////// EDGE + case SMDSEntity_Triangle: //// TRIANGLE + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: // TETRAHEDRON + { + break; + } + case SMDSEntity_Quad_Edge: + { + break; + } + case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE + { + if ( nbUniqueNodes < 3 ) + toRemove = true; + else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ]) + toRemove = true; // opposite nodes stick + else + toRemove = false; + break; + } + case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE + { + // 1 5 2 + // +---+---+ + // | | + // 4+ +6 + // | | + // +---+---+ + // 0 7 3 + if ( nbUniqueNodes == 6 && + iRepl[0] < 4 && + ( nbRepl == 1 || iRepl[1] >= 4 )) + { + toRemove = false; + } + break; + } + case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE + { + // 1 5 2 + // +---+---+ + // | | + // 4+ 8+ +6 + // | | + // +---+---+ + // 0 7 3 + if ( nbUniqueNodes == 7 && + iRepl[0] < 4 && + ( nbRepl == 1 || iRepl[1] != 8 )) + { + toRemove = false; + } + break; + } + case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON + { + if ( nbUniqueNodes == 4 ) { + // ---------------------------------> tetrahedron + if ( curNodes[3] == curNodes[4] && + curNodes[3] == curNodes[5] ) { + // top nodes stick + toRemove = false; + } + else if ( curNodes[0] == curNodes[1] && + curNodes[0] == curNodes[2] ) { + // bottom nodes stick: set a top before + uniqueNodes[ 3 ] = uniqueNodes [ 0 ]; + uniqueNodes[ 0 ] = curNodes [ 5 ]; + uniqueNodes[ 1 ] = curNodes [ 4 ]; + uniqueNodes[ 2 ] = curNodes [ 3 ]; + toRemove = false; + } + else if (( curNodes[0] == curNodes[3] ) + + ( curNodes[1] == curNodes[4] ) + + ( curNodes[2] == curNodes[5] ) == 2 ) { + // a lateral face turns into a line + toRemove = false; + } + } + else if ( nbUniqueNodes == 5 ) { + // PENTAHEDRON --------------------> pyramid + if ( curNodes[0] == curNodes[3] ) + { + uniqueNodes[ 0 ] = curNodes[ 1 ]; + uniqueNodes[ 1 ] = curNodes[ 4 ]; + uniqueNodes[ 2 ] = curNodes[ 5 ]; + uniqueNodes[ 3 ] = curNodes[ 2 ]; + uniqueNodes[ 4 ] = curNodes[ 0 ]; + toRemove = false; + } + if ( curNodes[1] == curNodes[4] ) + { + uniqueNodes[ 0 ] = curNodes[ 0 ]; + uniqueNodes[ 1 ] = curNodes[ 2 ]; + uniqueNodes[ 2 ] = curNodes[ 5 ]; + uniqueNodes[ 3 ] = curNodes[ 3 ]; + uniqueNodes[ 4 ] = curNodes[ 1 ]; + toRemove = false; + } + if ( curNodes[2] == curNodes[5] ) + { + uniqueNodes[ 0 ] = curNodes[ 0 ]; + uniqueNodes[ 1 ] = curNodes[ 3 ]; + uniqueNodes[ 2 ] = curNodes[ 4 ]; + uniqueNodes[ 3 ] = curNodes[ 1 ]; + uniqueNodes[ 4 ] = curNodes[ 2 ]; + toRemove = false; } - else if ( nbUniqueNodes == 6 && nbRepl == 4 ) { - ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism - // find indices of quad and tri faces - int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace; - for ( iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - nodeSet.clear(); - for ( iCur = 0; iCur < 4; iCur++ ) - nodeSet.insert( curNodes[ind[ iCur ]] ); - nbUniqueNodes = nodeSet.size(); - if ( nbUniqueNodes == 3 ) - iTriFace[ nbTri++ ] = iFace; - else if ( nbUniqueNodes == 4 ) - iQuadFace[ nbQuad++ ] = iFace; - } - if (nbQuad == 2 && nbTri == 4 && - hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) { - // 2 opposite quadrangles stuck with a diagonal; - // sample groups of merged indices: (0-4)(2-6) - // --------------------------------------------> 2 tetrahedrons - const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes - const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]); - int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top - if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] && - curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) { - // stuck with 0-2 diagonal - i0 = ind1[ 3 ]; - i1d = ind1[ 0 ]; - i2 = ind1[ 1 ]; - i3d = ind1[ 2 ]; - i0t = ind2[ 1 ]; - i2t = ind2[ 3 ]; - } - else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] && - curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) { - // stuck with 1-3 diagonal - i0 = ind1[ 0 ]; - i1d = ind1[ 1 ]; - i2 = ind1[ 2 ]; - i3d = ind1[ 3 ]; - i0t = ind2[ 0 ]; - i2t = ind2[ 1 ]; + } + break; + } + case SMDSEntity_Hexa: + { + //////////////////////////////////// HEXAHEDRON + SMDS_VolumeTool hexa (elem); + hexa.SetExternalNormal(); + if ( nbUniqueNodes == 4 && nbRepl == 4 ) { + //////////////////////// HEX ---> tetrahedron + for ( int iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { + // one face turns into a point ... + int pickInd = ind[ 0 ]; + int iOppFace = hexa.GetOppFaceIndex( iFace ); + ind = hexa.GetFaceNodesIndices( iOppFace ); + int nbStick = 0; + uniqueNodes.clear(); + for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) { + if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) + nbStick++; + else + uniqueNodes.push_back( curNodes[ind[ iCur ]]); } - else { - ASSERT(0); + if ( nbStick == 1 ) { + // ... and the opposite one - into a triangle. + // set a top node + uniqueNodes.push_back( curNodes[ pickInd ]); + toRemove = false; } - // tetrahedron 1 - uniqueNodes[ 0 ] = curNodes [ i0 ]; - uniqueNodes[ 1 ] = curNodes [ i1d ]; - uniqueNodes[ 2 ] = curNodes [ i3d ]; - uniqueNodes[ 3 ] = curNodes [ i0t ]; - nbUniqueNodes = 4; - // tetrahedron 2 - SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ], - curNodes[ i2 ], - curNodes[ i3d ], - curNodes[ i2t ]); - myLastCreatedElems.Append(newElem); - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - isOk = true; + break; } - else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5) - ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5) - // --------------------------------------------> prism - // find 2 opposite triangles - nbUniqueNodes = 6; - for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) { - if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) { - // find indices of kept and replaced nodes - // and fill unique nodes of 2 opposite triangles - const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]); - const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]); - const SMDS_MeshNode** hexanodes = hexa.GetNodes(); - // fill unique nodes - iUnique = 0; - isOk = true; - for ( iCur = 0; iCur < 4 && isOk; iCur++ ) { - const SMDS_MeshNode* n = curNodes[ind1[ iCur ]]; - const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]]; - if ( n == nInit ) { - // iCur of a linked node of the opposite face (make normals co-directed): - int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur; - // check that correspondent corners of triangles are linked - if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] )) - isOk = false; - else { - uniqueNodes[ iUnique ] = n; - uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]]; - iUnique++; - } - } - } + } + } + else if ( nbUniqueNodes == 6 && nbRepl == 2 ) { + //////////////////////// HEX ---> prism + int nbTria = 0, iTria[3]; + const int *ind; // indices of face nodes + // look for triangular faces + for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) { + ind = hexa.GetFaceNodesIndices( iFace ); + TIDSortedNodeSet faceNodes; + for ( iCur = 0; iCur < 4; iCur++ ) + faceNodes.insert( curNodes[ind[iCur]] ); + if ( faceNodes.size() == 3 ) + iTria[ nbTria++ ] = iFace; + } + // check if triangles are opposite + if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] )) + { + // set nodes of the bottom triangle + ind = hexa.GetFaceNodesIndices( iTria[ 0 ]); + vector indB; + for ( iCur = 0; iCur < 4; iCur++ ) + if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1]) + indB.push_back( ind[iCur] ); + if ( !hexa.IsForward() ) + std::swap( indB[0], indB[2] ); + for ( iCur = 0; iCur < 3; iCur++ ) + uniqueNodes[ iCur ] = curNodes[indB[iCur]]; + // set nodes of the top triangle + const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]); + for ( iCur = 0; iCur < 3; ++iCur ) + for ( int j = 0; j < 4; ++j ) + if ( hexa.IsLinked( indB[ iCur ], indT[ j ] )) + { + uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]]; break; } + toRemove = false; + break; + } + } + else if (nbUniqueNodes == 5 && nbRepl == 3 ) { + //////////////////// HEXAHEDRON ---> pyramid + for ( int iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { + // one face turns into a point ... + int iOppFace = hexa.GetOppFaceIndex( iFace ); + ind = hexa.GetFaceNodesIndices( iOppFace ); + uniqueNodes.clear(); + for ( iCur = 0; iCur < 4; iCur++ ) { + if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) + break; + else + uniqueNodes.push_back( curNodes[ind[ iCur ]]); } + if ( uniqueNodes.size() == 4 ) { + // ... and the opposite one is a quadrangle + // set a top node + const int* indTop = hexa.GetFaceNodesIndices( iFace ); + uniqueNodes.push_back( curNodes[indTop[ 0 ]]); + toRemove = false; + } + break; } - } // if ( nbUniqueNodes == 6 && nbRepl == 4 ) - else - { - MESSAGE("MergeNodes() removes hexahedron "<< elem); } - break; - } // HEXAHEDRON - - default: - isOk = false; - } // switch ( nbNodes ) - - } // if ( nbNodes != nbUniqueNodes ) // some nodes stick - - if ( isOk ) { // the elem remains valid after sticking nodes - if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) - { - // Change nodes of polyedre - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( 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); - } + if ( toRemove && nbUniqueNodes > 4 ) { + ////////////////// HEXAHEDRON ---> polyhedron + hexa.SetExternalNormal(); + vector& poly_nodes = newElemDefs[0].myNodes; + vector & quantities = newElemDefs[0].myPolyhedQuantities; + poly_nodes.reserve( 6 * 4 ); poly_nodes.clear(); + quantities.reserve( 6 ); quantities.clear(); + for ( int iFace = 0; iFace < 6; iFace++ ) + { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if ( curNodes[ind[0]] == curNodes[ind[2]] || + curNodes[ind[1]] == curNodes[ind[3]] ) + { + quantities.clear(); + break; // opposite nodes stick + } + nodeSet.clear(); + for ( iCur = 0; iCur < 4; iCur++ ) + { + if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second ) + poly_nodes.push_back( curNodes[ind[ iCur ]]); } - aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities ); + if ( nodeSet.size() < 3 ) + poly_nodes.resize( poly_nodes.size() - nodeSet.size() ); + else + quantities.push_back( nodeSet.size() ); + } + if ( quantities.size() >= 4 ) + { + nbResElems = 1; + nbUniqueNodes = poly_nodes.size(); + newElemDefs[0].SetPoly(true); } } - 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); + break; + } // case HEXAHEDRON - SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; + default: + toRemove = true; - aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); - SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId); - if ( sm && newElem ) - sm->AddElement( newElem ); - if ( elem != newElem ) - ReplaceElemInGroups( elem, newElem, aMesh ); - } - } - else { - // Remove invalid regular element or invalid polygon - rmElemIds.push_back( elem->GetID() ); + } // switch ( entity ) + + if ( toRemove && nbResElems == 0 && avoidMakingHoles ) + { + // erase from nodeNodeMap nodes whose merge spoils elem + vector< const SMDS_MeshNode* > noMergeNodes; + SMESH_MeshAlgos::DeMerge( elem, curNodes, noMergeNodes ); + for ( size_t i = 0; i < noMergeNodes.size(); ++i ) + nodeNodeMap.erase( noMergeNodes[i] ); } + + } // if ( nbNodes != nbUniqueNodes ) // some nodes stick - } // loop on elements + uniqueNodes.resize( nbUniqueNodes ); - // Remove bad elements, then equal nodes (order important) + if ( !toRemove && nbResElems == 0 ) + nbResElems = 1; - Remove( rmElemIds, false ); - Remove( rmNodeIds, true ); + newElemDefs.resize( nbResElems ); + return !toRemove; } // ======================================================== -// class : SortableElement -// purpose : allow sorting elements basing on their nodes +// class : ComparableElement +// purpose : allow comparing elements basing on their nodes // ======================================================== -class SortableElement : public set + +class ComparableElement : public boost::container::flat_set< int > { + typedef boost::container::flat_set< int > int_set; + + const SMDS_MeshElement* myElem; + int mySumID; + mutable int myGroupID; + public: - SortableElement( const SMDS_MeshElement* theElem ) + ComparableElement( const SMDS_MeshElement* theElem ): + myElem ( theElem ), mySumID( 0 ), myGroupID( -1 ) { - myElem = theElem; - SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); - while ( nodeIt->more() ) - this->insert( nodeIt->next() ); + this->reserve( theElem->NbNodes() ); + for ( SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); nodeIt->more(); ) + { + int id = nodeIt->next()->GetID(); + mySumID += id; + this->insert( id ); + } } - const SMDS_MeshElement* Get() const - { return myElem; } + const SMDS_MeshElement* GetElem() const { return myElem; } - void Set(const SMDS_MeshElement* e) const - { myElem = e; } + int& GroupID() const { return myGroupID; } + //int& GroupID() const { return const_cast< int& >( myGroupID ); } + ComparableElement( const ComparableElement& theSource ) // move copy + { + ComparableElement& src = const_cast< ComparableElement& >( theSource ); + (int_set&) (*this ) = boost::move( src ); + myElem = src.myElem; + mySumID = src.mySumID; + myGroupID = src.myGroupID; + } + + static int HashCode(const ComparableElement& se, int limit ) + { + return ::HashCode( se.mySumID, limit ); + } + static Standard_Boolean IsEqual(const ComparableElement& se1, const ComparableElement& se2 ) + { + return ( se1 == se2 ); + } -private: - mutable const SMDS_MeshElement* myElem; }; //======================================================================= @@ -7804,52 +7799,47 @@ private: // Search among theElements or in the whole mesh if theElements is empty //======================================================================= -void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements, - TListOfListOfElementsID & theGroupsOfElementsID) +void SMESH_MeshEditor::FindEqualElements( TIDSortedElemSet & theElements, + TListOfListOfElementsID & theGroupsOfElementsID ) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - typedef map< SortableElement, int > TMapOfNodeSet; - typedef list TGroupOfElems; + ClearLastCreated(); - if ( theElements.empty() ) - { // get all elements in the mesh - SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator(); - while ( eIt->more() ) - theElements.insert( theElements.end(), eIt->next()); - } + SMDS_ElemIteratorPtr elemIt; + if ( theElements.empty() ) elemIt = GetMeshDS()->elementsIterator(); + else elemIt = SMESHUtils::elemSetIterator( theElements ); - vector< TGroupOfElems > arrayOfGroups; - TGroupOfElems groupOfElems; - TMapOfNodeSet mapOfNodeSet; + typedef NCollection_Map< ComparableElement, ComparableElement > TMapOfElements; + typedef std::list TGroupOfElems; + TMapOfElements mapOfElements; + std::vector< TGroupOfElems > arrayOfGroups; + TGroupOfElems groupOfElems; - TIDSortedElemSet::iterator elemIt = theElements.begin(); - for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) { - const SMDS_MeshElement* curElem = *elemIt; - SortableElement SE(curElem); - int ind = -1; + while ( elemIt->more() ) + { + const SMDS_MeshElement* curElem = elemIt->next(); + ComparableElement compElem = curElem; // check uniqueness - pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i)); - if( !(pp.second) ) { - TMapOfNodeSet::iterator& itSE = pp.first; - ind = (*itSE).second; - arrayOfGroups[ind].push_back(curElem->GetID()); - } - else { - groupOfElems.clear(); - groupOfElems.push_back(curElem->GetID()); - arrayOfGroups.push_back(groupOfElems); - i++; + const ComparableElement& elemInSet = mapOfElements.Added( compElem ); + if ( elemInSet.GetElem() != curElem ) // coincident elem + { + int& iG = elemInSet.GroupID(); + if ( iG < 0 ) + { + iG = arrayOfGroups.size(); + arrayOfGroups.push_back( groupOfElems ); + arrayOfGroups[ iG ].push_back( elemInSet.GetElem()->GetID() ); + } + arrayOfGroups[ iG ].push_back( curElem->GetID() ); } } - vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin(); - for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) { - groupOfElems = *groupIt; - if ( groupOfElems.size() > 1 ) { - groupOfElems.sort(); - theGroupsOfElementsID.push_back(groupOfElems); + groupOfElems.clear(); + std::vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin(); + for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) + { + if ( groupIt->size() > 1 ) { + //groupOfElems.sort(); -- theElements are sorted already + theGroupsOfElementsID.emplace_back( *groupIt ); } } } @@ -7861,8 +7851,7 @@ void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements, void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); typedef list TListOfIDs; TListOfIDs rmElemIds; // IDs of elems to remove @@ -7901,8 +7890,8 @@ void SMESH_MeshEditor::MergeEqualElements() TIDSortedElemSet aMeshElements; /* empty input == to merge equal elements in the whole mesh */ TListOfListOfElementsID aGroupsOfElementsID; - FindEqualElements(aMeshElements, aGroupsOfElementsID); - MergeElements(aGroupsOfElementsID); + FindEqualElements( aMeshElements, aGroupsOfElementsID ); + MergeElements( aGroupsOfElementsID ); } //======================================================================= @@ -7920,6 +7909,24 @@ static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1, return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ); } +//======================================================================= +//function : findSegment +//purpose : Return a mesh segment by two nodes one of which can be medium +//======================================================================= + +static const SMDS_MeshElement* findSegment(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2) +{ + SMDS_ElemIteratorPtr it = n1->GetInverseElementIterator( SMDSAbs_Edge ); + while ( it->more() ) + { + const SMDS_MeshElement* seg = it->next(); + if ( seg->GetNodeIndex( n2 ) >= 0 ) + return seg; + } + return 0; +} + //======================================================================= //function : FindFreeBorder //purpose : @@ -7944,7 +7951,6 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirst theNodes.push_back( theFirstNode ); theNodes.push_back( theSecondNode ); - //vector nodes; const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode; TIDSortedElemSet foundElems; bool needTheLast = ( theLastNode != 0 ); @@ -7956,32 +7962,18 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirst // find all free border faces sharing form nStart list< const SMDS_MeshElement* > curElemList; - list< const SMDS_MeshNode* > nStartList; + list< const SMDS_MeshNode* > nStartList; SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face); while ( invElemIt->more() ) { const SMDS_MeshElement* e = invElemIt->next(); if ( e == curElem || foundElems.insert( e ).second ) { // get nodes int iNode = 0, nbNodes = e->NbNodes(); - //const SMDS_MeshNode* nodes[nbNodes+1]; - vector nodes(nbNodes+1); - - if(e->IsQuadratic()) { - const SMDS_VtkFace* F = - dynamic_cast(e); - if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); - // use special nodes iterator - SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); - while( anIter->more() ) { - nodes[ iNode++ ] = cast2Node(anIter->next()); - } - } - else { - SMDS_ElemIteratorPtr nIt = e->nodesIterator(); - while ( nIt->more() ) - nodes[ iNode++ ] = static_cast( nIt->next() ); - } - nodes[ iNode ] = nodes[ 0 ]; + vector nodes( nbNodes+1 ); + nodes.assign( SMDS_MeshElement::iterator( e->interlacedNodesIterator() ), + SMDS_MeshElement::iterator() ); + nodes.push_back( nodes[ 0 ]); + // check 2 links for ( iNode = 0; iNode < nbNodes; iNode++ ) if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) || @@ -8048,7 +8040,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirst if ( contNodes[0].empty() && contNodes[1].empty() ) return false; - // append the best free border + // push_back the best free border cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ]; cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ]; theNodes.pop_back(); // remove nIgnore @@ -8083,6 +8075,8 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, //======================================================================= //function : SewFreeBorder //purpose : +//warning : for border-to-side sewing theSideSecondNode is considered as +// the last side node and theSideThirdNode is not used //======================================================================= SMESH_MeshEditor::Sew_Error @@ -8096,19 +8090,17 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, const bool toCreatePolygons, const bool toCreatePolyedrs) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); - MESSAGE("::SewFreeBorder()"); Sew_Error aResult = SEW_OK; // ==================================== // find side nodes and elements // ==================================== - list< const SMDS_MeshNode* > nSide[ 2 ]; + list< const SMDS_MeshNode* > nSide[ 2 ]; list< const SMDS_MeshElement* > eSide[ 2 ]; - list< const SMDS_MeshNode* >::iterator nIt[ 2 ]; + list< const SMDS_MeshNode* >::iterator nIt[ 2 ]; list< const SMDS_MeshElement* >::iterator eIt[ 2 ]; // Free border 1 @@ -8144,7 +8136,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, // ------------------------------------------------------------------------- // 1. Since sewing may break if there are volumes to split on the side 2, - // we wont move nodes but just compute new coordinates for them + // we won't move nodes but just compute new coordinates for them typedef map TNodeXYZMap; TNodeXYZMap nBordXYZ; list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ]; @@ -8207,7 +8199,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, //const SMDS_MeshNode* faceNodes[ 4 ]; const SMDS_MeshNode* sideNode; - const SMDS_MeshElement* sideElem; + const SMDS_MeshElement* sideElem = 0; const SMDS_MeshNode* prevSideNode = theSideFirstNode; const SMDS_MeshNode* prevBordNode = theBordFirstNode; nBordIt = bordNodes.begin(); @@ -8232,33 +8224,19 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, { const SMDS_MeshElement* elem = invElemIt->next(); // prepare data for a loop on links coming to prevSideNode, of a face or a volume - int iPrevNode, iNode = 0, nbNodes = elem->NbNodes(); + int iPrevNode = 0, iNode = 0, nbNodes = elem->NbNodes(); vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 ); bool isVolume = volume.Set( elem ); const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0]; if ( isVolume ) // --volume hasVolumes = true; - else if ( elem->GetType()==SMDSAbs_Face ) { // --face + else if ( elem->GetType() == SMDSAbs_Face ) { // --face // retrieve all face nodes and find iPrevNode - an index of the prevSideNode - if(elem->IsQuadratic()) { - 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(); - while( anIter->more() ) { - nodes[ iNode ] = cast2Node(anIter->next()); - if ( nodes[ iNode++ ] == prevSideNode ) - iPrevNode = iNode - 1; - } - } - else { - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) { - nodes[ iNode ] = cast2Node( nIt->next() ); - if ( nodes[ iNode++ ] == prevSideNode ) - iPrevNode = iNode - 1; - } + SMDS_NodeIteratorPtr nIt = elem->interlacedNodesIterator(); + while ( nIt->more() ) { + nodes[ iNode ] = cast2Node( nIt->next() ); + if ( nodes[ iNode++ ] == prevSideNode ) + iPrevNode = iNode - 1; } // there are 2 links to check nbNodes = 2; @@ -8308,7 +8286,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, } // loop on inverse elements of prevSideNode if ( !sideNode ) { - MESSAGE(" Cant find path by links of the Side 2 "); + MESSAGE(" Can't find path by links of the Side 2 "); return SEW_BAD_SIDE_NODES; } sideNodes.push_back( sideNode ); @@ -8344,12 +8322,26 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, // sew the border to the side 2 // ============================ - int nbNodes[] = { nSide[0].size(), nSide[1].size() }; + int nbNodes[] = { (int)nSide[0].size(), (int)nSide[1].size() }; int maxNbNodes = Max( nbNodes[0], nbNodes[1] ); + bool toMergeConformal = ( nbNodes[0] == nbNodes[1] ); + if ( toMergeConformal && toCreatePolygons ) + { + // do not merge quadrangles if polygons are OK (IPAL0052824) + eIt[0] = eSide[0].begin(); + eIt[1] = eSide[1].begin(); + bool allQuads[2] = { true, true }; + for ( int iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders + for ( ; allQuads[iBord] && eIt[iBord] != eSide[iBord].end(); ++eIt[iBord] ) + allQuads[iBord] = ( (*eIt[iBord])->NbCornerNodes() == 4 ); + } + toMergeConformal = ( !allQuads[0] && !allQuads[1] ); + } + TListOfListOfNodes nodeGroupsToMerge; - if ( nbNodes[0] == nbNodes[1] || - ( theSideIsFreeBorder && !theSideThirdNode)) { + if (( toMergeConformal ) || + ( theSideIsFreeBorder && !theSideThirdNode )) { // all nodes are to be merged @@ -8367,10 +8359,9 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, // insert new nodes into the border and the side to get equal nb of segments // get normalized parameters of nodes on the borders - //double param[ 2 ][ maxNbNodes ]; - double* param[ 2 ]; - param[0] = new double [ maxNbNodes ]; - param[1] = new double [ maxNbNodes ]; + vector< double > param[ 2 ]; + param[0].resize( maxNbNodes ); + param[1].resize( maxNbNodes ); int iNode, iBord; for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders list< const SMDS_MeshNode* >& nodes = nSide[ iBord ]; @@ -8415,8 +8406,8 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, if ( i[ iBord ] > 0 ) prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]); } - double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); - double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); + double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); + double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); double minSegLen = Min( nextParam - minParam, maxParam - prevParam ); // choose to insert or to merge nodes @@ -8440,10 +8431,10 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, // insert // ------ int intoBord = ( du < 0 ) ? 0 : 1; - const SMDS_MeshElement* elem = *eIt[ intoBord ]; + const SMDS_MeshElement* elem = *eIt [ intoBord ]; const SMDS_MeshNode* n1 = nPrev[ intoBord ]; - const SMDS_MeshNode* n2 = *nIt[ intoBord ]; - const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ]; + const SMDS_MeshNode* n2 = *nIt [ intoBord ]; + const SMDS_MeshNode* nIns = *nIt [ 1 - intoBord ]; if ( intoBord == 1 ) { // move node of the border to be on a link of elem of the side gp_XYZ p1 (n1->X(), n1->Y(), n1->Z()); @@ -8453,7 +8444,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() ); } insertMapIt = insertMap.find( elem ); - bool notFound = ( insertMapIt == insertMap.end() ); + bool notFound = ( insertMapIt == insertMap.end() ); bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 ); if ( otherLink ) { // insert into another link of the same element: @@ -8463,12 +8454,11 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front(); InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons ); // 2. perform insertion into the link of adjacent faces - while (true) { - const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem ); - if ( adjElem ) - InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons ); - else - break; + while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem )) { + InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons ); + } + while ( const SMDS_MeshElement* seg = findSegment( n12, n22 )) { + InsertNodesIntoLink( seg, n12, n22, nodeList ); } if (toCreatePolyedrs) { // perform insertion into the links of adjacent volumes @@ -8480,8 +8470,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, } if ( notFound || otherLink ) { // add element and nodes of the side into the insertMap - insertMapIt = insertMap.insert - ( TElemOfNodeListMap::value_type( elem, list() )).first; + insertMapIt = insertMap.insert( make_pair( elem, list() )).first; (*insertMapIt).second.push_back( n1 ); (*insertMapIt).second.push_back( n2 ); } @@ -8515,14 +8504,14 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons ); + while ( const SMDS_MeshElement* seg = findSegment( n1, n2 )) { + InsertNodesIntoLink( seg, n1, n2, nodeList ); + } + if ( !theSideIsFreeBorder ) { // look for and insert nodes into the faces adjacent to elem - while (true) { - const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem ); - if ( adjElem ) - InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons ); - else - break; + while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem )) { + InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons ); } } if (toCreatePolyedrs) { @@ -8530,69 +8519,156 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, UpdateVolumes(n1, n2, nodeList); } } - - delete param[0]; - delete param[1]; } // end: insert new nodes MergeNodes ( nodeGroupsToMerge ); + + // Remove coincident segments + + // get new segments + TIDSortedElemSet segments; + SMESH_SequenceOfElemPtr newFaces; + for ( size_t i = 0; i < myLastCreatedElems.size(); ++i ) + { + if ( !myLastCreatedElems[i] ) continue; + if ( myLastCreatedElems[i]->GetType() == SMDSAbs_Edge ) + segments.insert( segments.end(), myLastCreatedElems[i] ); + else + newFaces.push_back( myLastCreatedElems[i] ); + } + // get segments adjacent to merged nodes + TListOfListOfNodes::iterator groupIt = nodeGroupsToMerge.begin(); + for ( ; groupIt != nodeGroupsToMerge.end(); groupIt++ ) + { + const list& nodes = *groupIt; + if ( nodes.front()->IsNull() ) continue; + SMDS_ElemIteratorPtr segIt = nodes.front()->GetInverseElementIterator( SMDSAbs_Edge ); + while ( segIt->more() ) + segments.insert( segIt->next() ); + } + + // find coincident + TListOfListOfElementsID equalGroups; + if ( !segments.empty() ) + FindEqualElements( segments, equalGroups ); + if ( !equalGroups.empty() ) + { + // remove from segments those that will be removed + TListOfListOfElementsID::iterator itGroups = equalGroups.begin(); + for ( ; itGroups != equalGroups.end(); ++itGroups ) + { + list< int >& group = *itGroups; + list< int >::iterator id = group.begin(); + for ( ++id; id != group.end(); ++id ) + if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id )) + segments.erase( seg ); + } + // remove equal segments + MergeElements( equalGroups ); + + // restore myLastCreatedElems + myLastCreatedElems = newFaces; + TIDSortedElemSet::iterator seg = segments.begin(); + for ( ; seg != segments.end(); ++seg ) + myLastCreatedElems.push_back( *seg ); + } + return aResult; } //======================================================================= //function : InsertNodesIntoLink -//purpose : insert theNodesToInsert into theFace between theBetweenNode1 +//purpose : insert theNodesToInsert into theElement between theBetweenNode1 // and theBetweenNode2 and split theElement //======================================================================= -void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, +void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theElement, const SMDS_MeshNode* theBetweenNode1, const SMDS_MeshNode* theBetweenNode2, list& theNodesToInsert, const bool toCreatePoly) { + if ( !theElement ) return; + + SMESHDS_Mesh *aMesh = GetMeshDS(); + vector newElems; + + if ( theElement->GetType() == SMDSAbs_Edge ) + { + theNodesToInsert.push_front( theBetweenNode1 ); + theNodesToInsert.push_back ( theBetweenNode2 ); + list::iterator n = theNodesToInsert.begin(); + const SMDS_MeshNode* n1 = *n; + for ( ++n; n != theNodesToInsert.end(); ++n ) + { + const SMDS_MeshNode* n2 = *n; + if ( const SMDS_MeshElement* seg = aMesh->FindEdge( n1, n2 )) + AddToSameGroups( seg, theElement, aMesh ); + else + newElems.push_back( aMesh->AddEdge ( n1, n2 )); + n1 = n2; + } + theNodesToInsert.pop_front(); + theNodesToInsert.pop_back(); + + if ( theElement->IsQuadratic() ) // add a not split part + { + vector nodes( theElement->begin_nodes(), + theElement->end_nodes() ); + int iOther = 0, nbN = nodes.size(); + for ( ; iOther < nbN; ++iOther ) + if ( nodes[iOther] != theBetweenNode1 && + nodes[iOther] != theBetweenNode2 ) + break; + if ( iOther == 0 ) + { + if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[0], nodes[1] )) + AddToSameGroups( seg, theElement, aMesh ); + else + newElems.push_back( aMesh->AddEdge ( nodes[0], nodes[1] )); + } + else if ( iOther == 2 ) + { + if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[1], nodes[2] )) + AddToSameGroups( seg, theElement, aMesh ); + else + newElems.push_back( aMesh->AddEdge ( nodes[1], nodes[2] )); + } + } + // treat new elements + for ( size_t i = 0; i < newElems.size(); ++i ) + if ( newElems[i] ) + { + aMesh->SetMeshElementOnShape( newElems[i], theElement->getshapeId() ); + myLastCreatedElems.push_back( newElems[i] ); + } + ReplaceElemInGroups( theElement, newElems, aMesh ); + aMesh->RemoveElement( theElement ); + return; + + } // if ( theElement->GetType() == SMDSAbs_Edge ) + + const SMDS_MeshElement* theFace = theElement; if ( theFace->GetType() != SMDSAbs_Face ) return; // find indices of 2 link nodes and of the rest nodes int iNode = 0, il1, il2, i3, i4; il1 = il2 = i3 = i4 = -1; - //const SMDS_MeshNode* nodes[ theFace->NbNodes() ]; vector nodes( theFace->NbNodes() ); - if(theFace->IsQuadratic()) { - const SMDS_VtkFace* F = - dynamic_cast(theFace); - if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); - // use special nodes iterator - SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); - while( anIter->more() ) { - const SMDS_MeshNode* n = cast2Node(anIter->next()); - if ( n == theBetweenNode1 ) - il1 = iNode; - else if ( n == theBetweenNode2 ) - il2 = iNode; - else if ( i3 < 0 ) - i3 = iNode; - else - i4 = iNode; - nodes[ iNode++ ] = n; - } - } - else { - SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - if ( n == theBetweenNode1 ) - il1 = iNode; - else if ( n == theBetweenNode2 ) - il2 = iNode; - else if ( i3 < 0 ) - i3 = iNode; - else - i4 = iNode; - nodes[ iNode++ ] = n; - } + SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = nodeIt->next(); + if ( n == theBetweenNode1 ) + il1 = iNode; + else if ( n == theBetweenNode2 ) + il2 = iNode; + else if ( i3 < 0 ) + i3 = iNode; + else + i4 = iNode; + nodes[ iNode++ ] = n; } if ( il1 < 0 || il2 < 0 || i3 < 0 ) return ; @@ -8621,73 +8697,29 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, // add nodes of face up to first node of link bool isFLN = false; - - if(theFace->IsQuadratic()) { - const SMDS_VtkFace* F = - dynamic_cast(theFace); - if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); - // use special nodes iterator - SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); - while( anIter->more() && !isFLN ) { - const SMDS_MeshNode* n = cast2Node(anIter->next()); - poly_nodes[iNode++] = n; - if (n == nodes[il1]) { - isFLN = true; - } - } - // add nodes to insert - list::iterator nIt = aNodesToInsert.begin(); - for (; nIt != aNodesToInsert.end(); nIt++) { - poly_nodes[iNode++] = *nIt; - } - // add nodes of face starting from last node of link - while ( anIter->more() ) { - poly_nodes[iNode++] = cast2Node(anIter->next()); - } + SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator(); + while ( nodeIt->more() && !isFLN ) { + const SMDS_MeshNode* n = nodeIt->next(); + poly_nodes[iNode++] = n; + isFLN = ( n == nodes[il1] ); } - else { - SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); - while ( nodeIt->more() && !isFLN ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - poly_nodes[iNode++] = n; - if (n == nodes[il1]) { - isFLN = true; - } - } - // add nodes to insert - list::iterator nIt = aNodesToInsert.begin(); - for (; nIt != aNodesToInsert.end(); nIt++) { - poly_nodes[iNode++] = *nIt; - } - // add nodes of face starting from last node of link - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - poly_nodes[iNode++] = n; - } + // add nodes to insert + list::iterator nIt = aNodesToInsert.begin(); + for (; nIt != aNodesToInsert.end(); nIt++) { + poly_nodes[iNode++] = *nIt; } - - // edit or replace the face - SMESHDS_Mesh *aMesh = GetMeshDS(); - - if (theFace->IsPoly()) { - aMesh->ChangePolygonNodes(theFace, poly_nodes); + // add nodes of face starting from last node of link + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + poly_nodes[iNode++] = n; } - else { - int aShapeId = FindShape( theFace ); - SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - - aMesh->RemoveElement(theFace); - } - return; + // make a new face + newElems.push_back( aMesh->AddPolygonalFace( poly_nodes )); } - SMESHDS_Mesh *aMesh = GetMeshDS(); - if( !theFace->IsQuadratic() ) { - + else if ( !theFace->IsQuadratic() ) + { // put aNodesToInsert between theBetweenNode1 and theBetweenNode2 int nbLinkNodes = 2 + aNodesToInsert.size(); //const SMDS_MeshNode* linkNodes[ nbLinkNodes ]; @@ -8700,7 +8732,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, } // decide how to split a quadrangle: compare possible variants // and choose which of splits to be a quadrangle - int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad; + int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad = 0; if ( nbFaceNodes == 3 ) { iBestQuad = nbSplits; i4 = i3; @@ -8736,41 +8768,32 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, } // create new elements - int aShapeId = FindShape( theFace ); - i1 = 0; i2 = 1; - for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) { - SMDS_MeshElement* newElem = 0; + for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) + { if ( iSplit == iBestQuad ) - newElem = aMesh->AddFace (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ i3 ], - nodes[ i4 ]); + newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ i3 ], + nodes[ i4 ])); else - newElem = aMesh->AddFace (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ iSplit < iBestQuad ? i4 : i3 ]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ iSplit < iBestQuad ? i4 : i3 ])); } - // change nodes of theFace const SMDS_MeshNode* newNodes[ 4 ]; newNodes[ 0 ] = linkNodes[ i1 ]; newNodes[ 1 ] = linkNodes[ i2 ]; newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ]; newNodes[ 3 ] = nodes[ i4 ]; - //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 ); - const SMDS_MeshElement* newElem = 0; if (iSplit == iBestQuad) - newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] ); + newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] )); else - newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] ); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); -} // end if(!theFace->IsQuadratic()) + newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] )); + + } // end if(!theFace->IsQuadratic()) + else { // theFace is quadratic // we have to split theFace on simple triangles and one simple quadrangle int tmp = il1/2; @@ -8797,66 +8820,38 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, // n4 n6 n5 n4 // create new elements - int aShapeId = FindShape( theFace ); - int n1,n2,n3; - if(nbFaceNodes==6) { // quadratic triangle - SMDS_MeshElement* newElem = - aMesh->AddFace(nodes[3],nodes[4],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - if(theFace->IsMediumNode(nodes[il1])) { + if ( nbFaceNodes == 6 ) { // quadratic triangle + newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] )); + if ( theFace->IsMediumNode(nodes[il1]) ) { // create quadrangle - newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[5] )); n1 = 1; n2 = 2; n3 = 3; } else { // create quadrangle - newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[5] )); n1 = 0; n2 = 1; n3 = 5; } } else { // nbFaceNodes==8 - quadratic quadrangle - SMDS_MeshElement* newElem = - aMesh->AddFace(nodes[3],nodes[4],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - if(theFace->IsMediumNode(nodes[il1])) { + newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] )); + newElems.push_back( aMesh->AddFace( nodes[5], nodes[6], nodes[7] )); + newElems.push_back( aMesh->AddFace( nodes[5], nodes[7], nodes[3] )); + if ( theFace->IsMediumNode( nodes[ il1 ])) { // create quadrangle - newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[7] )); n1 = 1; n2 = 2; n3 = 3; } else { // create quadrangle - newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[7] )); n1 = 0; n2 = 1; n3 = 7; @@ -8864,36 +8859,39 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, } // create needed triangles using n1,n2,n3 and inserted nodes int nbn = 2 + aNodesToInsert.size(); - //const SMDS_MeshNode* aNodes[nbn]; vector aNodes(nbn); - aNodes[0] = nodes[n1]; + aNodes[0 ] = nodes[n1]; aNodes[nbn-1] = nodes[n2]; list::iterator nIt = aNodesToInsert.begin(); for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { aNodes[iNode++] = *nIt; } - for(i=1; iAddFace(aNodes[i-1],aNodes[i],nodes[n3]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } + for ( i = 1; i < nbn; i++ ) + newElems.push_back( aMesh->AddFace( aNodes[i-1], aNodes[i], nodes[n3] )); } - // remove old face + + // remove the old face + for ( size_t i = 0; i < newElems.size(); ++i ) + if ( newElems[i] ) + { + aMesh->SetMeshElementOnShape( newElems[i], theFace->getshapeId() ); + myLastCreatedElems.push_back( newElems[i] ); + } + ReplaceElemInGroups( theFace, newElems, aMesh ); aMesh->RemoveElement(theFace); -} + +} // InsertNodesIntoLink() //======================================================================= //function : UpdateVolumes //purpose : //======================================================================= + void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1, const SMDS_MeshNode* theBetweenNode2, list& theNodesToInsert) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume); while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1 @@ -8949,24 +8947,16 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode quantities[iface] = nbFaceNodes + nbInserted; } - // Replace or update the volume + // Replace the volume SMESHDS_Mesh *aMesh = GetMeshDS(); - if (elem->IsPoly()) { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - - } - else { - int aShapeId = FindShape( elem ); - - SMDS_MeshElement* newElem = - aMesh->AddPolyhedralVolume(poly_nodes, quantities); - myLastCreatedElems.Append(newElem); - if (aShapeId && newElem) - aMesh->SetMeshElementOnShape(newElem, aShapeId); - - aMesh->RemoveElement(elem); + if ( SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities )) + { + aMesh->SetMeshElementOnShape( newElem, elem->getshapeId() ); + myLastCreatedElems.push_back( newElem ); + ReplaceElemInGroups( elem, newElem, aMesh ); } + aMesh->RemoveElement( elem ); } } @@ -8996,7 +8986,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 */ //======================================================================= @@ -9005,6 +8995,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, SMESH_MesherHelper& theHelper, const bool theForce3d) { + //MESSAGE("convertElemToQuadratic"); int nbElem = 0; if( !theSm ) return nbElem; @@ -9030,18 +9021,20 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, case SMDSEntity_Quad_Triangle: case SMDSEntity_Quad_Quadrangle: case SMDSEntity_Quad_Hexa: + case SMDSEntity_Quad_Penta: alreadyOK = !theHelper.GetIsBiQuadratic(); break; case SMDSEntity_BiQuad_Triangle: case SMDSEntity_BiQuad_Quadrangle: case SMDSEntity_TriQuad_Hexa: + case SMDSEntity_BiQuad_Penta: alreadyOK = theHelper.GetIsBiQuadratic(); hasCentralNodes = true; break; default: alreadyOK = true; } - // take into account already present modium nodes + // take into account already present medium nodes switch ( aType ) { case SMDSAbs_Volume: theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break; @@ -9060,14 +9053,14 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, const int nbNodes = elem->NbCornerNodes(); nodes.assign(elem->begin_nodes(), elem->end_nodes()); if ( aGeomType == SMDSEntity_Polyhedra ) - nbNodeInFaces = static_cast( elem )->GetQuantities(); + nbNodeInFaces = static_cast( elem )->GetQuantities(); else if ( aGeomType == SMDSEntity_Hexagonal_Prism ) volumeToPolyhedron( elem, nodes, nbNodeInFaces ); // remove a linear element GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); - // remove central nodes of biquadratic elements (biquad->quad convertion) + // remove central nodes of biquadratic elements (biquad->quad conversion) if ( hasCentralNodes ) for ( size_t i = nbNodes * 2; i < nodes.size(); ++i ) if ( nodes[i]->NbInverseElements() == 0 ) @@ -9078,50 +9071,52 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, switch( aType ) { case SMDSAbs_Edge : - { - NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d); - break; - } + { + NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d); + break; + } case SMDSAbs_Face : + { + switch(nbNodes) { - switch(nbNodes) - { - case 3: - NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); - break; - case 4: - NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); - break; - default: - NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d); - } + case 3: + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); + break; + case 4: + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); break; + default: + NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d); } + break; + } case SMDSAbs_Volume : + { + switch( aGeomType ) { - switch( aGeomType ) - { - case SMDSEntity_Tetra: - NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); - break; - case SMDSEntity_Pyramid: - NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d); - break; - case SMDSEntity_Penta: - 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; - case SMDSEntity_Hexagonal_Prism: - default: - NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); - } + case SMDSEntity_Tetra: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + case SMDSEntity_Pyramid: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d); + break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + case SMDSEntity_BiQuad_Penta: + 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; + case SMDSEntity_Hexagonal_Prism: + default: + NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); } + break; + } default : continue; } @@ -9138,6 +9133,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad) { + //MESSAGE("ConvertToQuadratic "<< theForce3d << " " << theToBiQuad); SMESHDS_Mesh* meshDS = GetMeshDS(); SMESH_MesherHelper aHelper(*myMesh); @@ -9265,6 +9261,8 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT { case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break; case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break; + case SMDSEntity_Quad_Penta: alreadyOK = !theToBiQuad; break; + case SMDSEntity_BiQuad_Penta: alreadyOK = theToBiQuad; break; default: alreadyOK = true; } if ( alreadyOK ) @@ -9276,7 +9274,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT const int id = volume->GetID(); vector nodes (volume->begin_nodes(), volume->end_nodes()); if ( type == SMDSEntity_Polyhedra ) - nbNodeInFaces = static_cast(volume)->GetQuantities(); + nbNodeInFaces = static_cast(volume)->GetQuantities(); else if ( type == SMDSEntity_Hexagonal_Prism ) volumeToPolyhedron( volume, nodes, nbNodeInFaces ); @@ -9302,8 +9300,13 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT nodes[3], nodes[4], id, theForce3d); break; case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + case SMDSEntity_BiQuad_Penta: NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d); + for ( size_t i = 15; i < nodes.size(); ++i ) // rm central nodes + if ( nodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true ); break; case SMDSEntity_Hexagonal_Prism: default: @@ -9491,7 +9494,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, if( newElem && smDS ) smDS->AddElement( newElem ); - // remove central nodes + // 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 ); @@ -9519,6 +9522,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int nbElem = 0; SMESHDS_Mesh* meshDS = GetMeshDS(); + ElemFeatures elemType; + vector nodes; while( theItr->more() ) { @@ -9526,11 +9531,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 )) @@ -9538,13 +9543,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 ); @@ -9623,7 +9628,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) } // replace given elements by linear ones - SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements ); + SMDS_ElemIteratorPtr elemIt = SMESHUtils::elemSetIterator( theElements ); removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs @@ -9675,7 +9680,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) } } } - elemIt = elemSetIterator( moreElemsToConvert ); + elemIt = SMESHUtils::elemSetIterator( moreElemsToConvert ); removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); } @@ -9692,10 +9697,8 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, const SMDS_MeshNode* theSecondNode1, const SMDS_MeshNode* theSecondNode2) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); - MESSAGE ("::::SewSideElements()"); if ( theSide1.size() != theSide2.size() ) return SEW_DIFF_NB_OF_ELEMENTS; @@ -9714,7 +9717,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // face does not exist SMESHDS_Mesh* aMesh = GetMeshDS(); - // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes + // TODO algorithm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh TIDSortedElemSet faceSet1, faceSet2; set volSet1, volSet2; @@ -9970,12 +9973,12 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, if ( faceSet1.size() != faceSet2.size() ) { // delete temporary faces: they are in reverseElements of actual nodes -// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); -// while ( tmpFaceIt->more() ) -// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); -// list::iterator tmpFaceIt = tempFaceList.begin(); -// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) -// aMesh->RemoveElement(*tmpFaceIt); + // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); + // while ( tmpFaceIt->more() ) + // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); + // list::iterator tmpFaceIt = tempFaceList.begin(); + // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) + // aMesh->RemoveElement(*tmpFaceIt); MESSAGE("Diff nb of faces"); return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } @@ -10033,20 +10036,8 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, //cout << " F " << face[ iSide]->GetID() <erase( face[ iSide ]); // put face nodes to fnodes - if ( face[ iSide ]->IsQuadratic() ) - { - // use interlaced nodes iterator - const SMDS_VtkFace* F = dynamic_cast( face[ iSide ]); - if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); - SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator(); - while ( nIter->more() ) - fnodes[ iSide ].push_back( cast2Node( nIter->next() )); - } - else - { - fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(), - face[ iSide ]->end_nodes() ); - } + SMDS_MeshElement::iterator nIt( face[ iSide ]->interlacedNodesIterator() ), nEnd; + fnodes[ iSide ].assign( nIt, nEnd ); fnodes[ iSide ].push_back( fnodes[ iSide ].front()); } } @@ -10114,7 +10105,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, if ( aResult == SEW_OK && ( //linkIt[0] != linkList[0].end() || - !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) { + !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) { MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) << " " << (faceSetPtr[1]->empty())); aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; @@ -10125,9 +10116,9 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // ==================================================================== // delete temporary faces -// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); -// while ( tmpFaceIt->more() ) -// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); + // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); + // while ( tmpFaceIt->more() ) + // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); list::iterator tmpFaceIt = tempFaceList.begin(); for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) aMesh->RemoveElement(*tmpFaceIt); @@ -10135,11 +10126,15 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, if ( aResult != SEW_OK) return aResult; - list< int > 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 @@ -10148,11 +10143,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++; @@ -10164,21 +10158,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 ); } + } } } @@ -10360,287 +10350,790 @@ 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 ) +namespace // automatically find theAffectedElems for DoubleNodes() { - ClearLastCreated(); - SMESHDS_Mesh* mesh = GetMeshDS(); + bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem ); - // 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 + //-------------------------------------------------------------------------------- + // Nodes shared by adjacent FissureBorder's. + // 1 node if FissureBorder separates faces + // 2 nodes if FissureBorder separates volumes + struct SubBorder { - type = (*theElements.begin())->GetType(); - elemIt = elemSetIterator( theElements ); - } - - // duplicate elements + const SMDS_MeshNode* _nodes[2]; + int _nbNodes; - if ( type == SMDSAbs_Ball ) - { - SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid(); - while ( elemIt->more() ) + SubBorder( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 = 0 ) { - const SMDS_MeshElement* elem = elemIt->next(); - if ( elem->GetType() != SMDSAbs_Ball ) - continue; - if (( elem = mesh->AddBall( elem->GetNode(0), - vtkGrid->GetBallDiameter( elem->getVtkId() )))) - myLastCreatedElems.Append( elem ); + _nodes[0] = n1; + _nodes[1] = n2; + _nbNodes = bool( n1 ) + bool( n2 ); + if ( _nbNodes == 2 && n1 > n2 ) + std::swap( _nodes[0], _nodes[1] ); } - } - else - { - vector< const SMDS_MeshNode* > nodes; - while ( elemIt->more() ) + bool operator<( const SubBorder& other ) const { - const SMDS_MeshElement* elem = elemIt->next(); - if ( elem->GetType() != type ) - continue; - - nodes.assign( elem->begin_nodes(), elem->end_nodes() ); - - if ( type == SMDSAbs_Volume && elem->GetVtkType() == VTK_POLYHEDRON ) - { - std::vector quantities = - static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities(); - elem = mesh->AddPolyhedralVolume( nodes, quantities ); - } - else + for ( int i = 0; i < _nbNodes; ++i ) { - AddElement( nodes, type, elem->IsPoly() ); - elem = 0; // myLastCreatedElems is already filled + if ( _nodes[i] < other._nodes[i] ) return true; + if ( _nodes[i] > other._nodes[i] ) return false; } - if ( elem ) - myLastCreatedElems.Append( elem ); + return false; } - } -} + }; -//================================================================================ -/*! - \brief Creates a hole in a mesh by doubling the nodes of some particular elements - \param theElems - the list of elements (edges or faces) to be replicated - The nodes for duplication could be found from these elements - \param theNodesNot - list of nodes to NOT replicate - \param theAffectedElems - the list of elements (cells and edges) to which the - replicated nodes should be associated to. - \return TRUE if operation has been completed successfully, FALSE otherwise -*/ -//================================================================================ + //-------------------------------------------------------------------------------- + // Map a SubBorder to all FissureBorder it bounds + struct FissureBorder; + typedef std::map< SubBorder, std::vector< FissureBorder* > > TBorderLinks; + typedef TBorderLinks::iterator TMappedSub; -bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, - const TIDSortedElemSet& theNodesNot, - const TIDSortedElemSet& theAffectedElems ) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + //-------------------------------------------------------------------------------- + /*! + * \brief Element border (volume facet or face edge) at a fissure + */ + struct FissureBorder + { + std::vector< const SMDS_MeshNode* > _nodes; // border nodes + const SMDS_MeshElement* _elems[2]; // volume or face adjacent to fissure - if ( theElems.size() == 0 ) - return false; + std::vector< TMappedSub > _mappedSubs; // Sub() in TBorderLinks map + std::vector< const SMDS_MeshNode* > _sortedNodes; // to compare FissureBorder's - SMESHDS_Mesh* aMeshDS = GetMeshDS(); - if ( !aMeshDS ) - return false; + FissureBorder( FissureBorder && from ) // move constructor + { + std::swap( _nodes, from._nodes ); + std::swap( _sortedNodes, from._sortedNodes ); + _elems[0] = from._elems[0]; + _elems[1] = from._elems[1]; + } - bool res = false; - std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; - // duplicate elements and nodes - res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true ); - // replce nodes by duplications - res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false ); - return res; -} + FissureBorder( const SMDS_MeshElement* elemToDuplicate, + std::vector< const SMDS_MeshElement* > & adjElems) + : _nodes( elemToDuplicate->NbCornerNodes() ) + { + for ( size_t i = 0; i < _nodes.size(); ++i ) + _nodes[i] = elemToDuplicate->GetNode( i ); -//================================================================================ -/*! - \brief Creates a hole in a mesh by doubling the nodes of some particular elements - \param theMeshDS - mesh instance - \param theElems - the elements replicated or modified (nodes should be changed) - \param theNodesNot - nodes to NOT replicate - \param theNodeNodeMap - relation of old node to new created node - \param theIsDoubleElem - flag os to replicate element or modify - \return TRUE if operation has been completed successfully, FALSE otherwise -*/ -//================================================================================ + SMDSAbs_ElementType type = SMDSAbs_ElementType( elemToDuplicate->GetType() + 1 ); + findAdjacent( type, adjElems ); + } -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 ) -{ - MESSAGE("doubleNodes"); - // iterate on through element and duplicate them (by nodes duplication) - bool res = false; - TIDSortedElemSet::const_iterator elemItr = theElems.begin(); - for ( ; elemItr != theElems.end(); ++elemItr ) - { - const SMDS_MeshElement* anElem = *elemItr; - if (!anElem) - continue; + FissureBorder( const SMDS_MeshNode** nodes, + const size_t nbNodes, + const SMDSAbs_ElementType adjElemsType, + std::vector< const SMDS_MeshElement* > & adjElems) + : _nodes( nodes, nodes + nbNodes ) + { + findAdjacent( adjElemsType, adjElems ); + } - bool isDuplicate = false; - // duplicate nodes to duplicate element - std::vector newNodes( anElem->NbNodes() ); - SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); - int ind = 0; - while ( anIter->more() ) + void findAdjacent( const SMDSAbs_ElementType adjElemsType, + std::vector< const SMDS_MeshElement* > & adjElems) + { + _elems[0] = _elems[1] = 0; + adjElems.clear(); + if ( SMDS_Mesh::GetElementsByNodes( _nodes, adjElems, adjElemsType )) + for ( size_t i = 0; i < adjElems.size() && i < 2; ++i ) + _elems[i] = adjElems[i]; + } + + bool operator<( const FissureBorder& other ) const { + return GetSortedNodes() < other.GetSortedNodes(); + } - 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() ) + const std::vector< const SMDS_MeshNode* >& GetSortedNodes() const + { + if ( _sortedNodes.empty() && !_nodes.empty() ) { - // duplicate node - aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); - copyPosition( aCurrNode, aNewNode ); - theNodeNodeMap[ aCurrNode ] = aNewNode; - myLastCreatedNodes.Append( aNewNode ); + FissureBorder* me = const_cast( this ); + me->_sortedNodes = me->_nodes; + std::sort( me->_sortedNodes.begin(), me->_sortedNodes.end() ); } - isDuplicate |= (aCurrNode != aNewNode); - newNodes[ ind++ ] = aNewNode; + return _sortedNodes; } - if ( !isDuplicate ) - continue; - - if ( theIsDoubleElem ) - AddElement(newNodes, anElem->GetType(), anElem->IsPoly()); - else - theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() ); - - res = true; - } - return res; -} -//================================================================================ -/*! - \brief Creates a hole in a mesh by doubling the nodes of some particular elements - \param theNodes - identifiers of nodes to be doubled - \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 -*/ -//================================================================================ + size_t NbSub() const + { + return _nodes.size(); + } -bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, - const std::list< int >& theListOfModifiedElems ) -{ - MESSAGE("DoubleNodes"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + SubBorder Sub(size_t i) const + { + return SubBorder( _nodes[i], NbSub() > 2 ? _nodes[ (i+1)%NbSub() ] : 0 ); + } - if ( theListOfNodes.size() == 0 ) - return false; + void AddSelfTo( TBorderLinks& borderLinks ) + { + _mappedSubs.resize( NbSub() ); + for ( size_t i = 0; i < NbSub(); ++i ) + { + TBorderLinks::iterator s2b = + borderLinks.insert( std::make_pair( Sub(i), TBorderLinks::mapped_type() )).first; + s2b->second.push_back( this ); + _mappedSubs[ i ] = s2b; + } + } - SMESHDS_Mesh* aMeshDS = GetMeshDS(); - if ( !aMeshDS ) - return false; + void Clear() + { + _nodes.clear(); + } - // iterate through nodes and duplicate them + const SMDS_MeshElement* GetMarkedElem() const + { + if ( _nodes.empty() ) return 0; // cleared + if ( _elems[0] && _elems[0]->isMarked() ) return _elems[0]; + if ( _elems[1] && _elems[1]->isMarked() ) return _elems[1]; + return 0; + } - std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + gp_XYZ GetNorm() const // normal to the border + { + gp_XYZ norm; + if ( _nodes.size() == 2 ) + { + gp_XYZ avgNorm( 0,0,0 ); // sum of normals of adjacent faces + if ( SMESH_MeshAlgos::FaceNormal( _elems[0], norm )) + avgNorm += norm; + if ( SMESH_MeshAlgos::FaceNormal( _elems[1], norm )) + avgNorm += norm; - std::list< int >::const_iterator aNodeIter; - for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter ) - { - int aCurr = *aNodeIter; - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr ); - if ( !aNode ) - continue; + gp_XYZ bordDir( SMESH_NodeXYZ( _nodes[0] ) - SMESH_NodeXYZ( _nodes[1] )); + norm = bordDir ^ avgNorm; + } + else + { + SMESH_NodeXYZ p0( _nodes[0] ); + SMESH_NodeXYZ p1( _nodes[1] ); + SMESH_NodeXYZ p2( _nodes[2] ); + norm = ( p0 - p1 ) ^ ( p2 - p1 ); + } + if ( isOut( _nodes[0], norm, GetMarkedElem() )) + norm.Reverse(); - // duplicate node + return norm; + } - const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); - if ( aNewNode ) + void ChooseSide() // mark an _elem located at positive side of fissure { - copyPosition( aNode, aNewNode ); - anOldNodeToNewNode[ aNode ] = aNewNode; - myLastCreatedNodes.Append( aNewNode ); + _elems[0]->setIsMarked( true ); + gp_XYZ norm = GetNorm(); + double maxX = norm.Coord(1); + if ( Abs( maxX ) < Abs( norm.Coord(2)) ) maxX = norm.Coord(2); + if ( Abs( maxX ) < Abs( norm.Coord(3)) ) maxX = norm.Coord(3); + if ( maxX < 0 ) + { + _elems[0]->setIsMarked( false ); + _elems[1]->setIsMarked( true ); + } } - } - - // Create map of new nodes for modified elements - std::map< SMDS_MeshElement*, vector > anElemToNodes; + }; // struct FissureBorder - std::list< int >::const_iterator anElemIter; - for ( anElemIter = theListOfModifiedElems.begin(); - anElemIter != theListOfModifiedElems.end(); ++anElemIter ) + //-------------------------------------------------------------------------------- + /*! + * \brief Classifier of elements at fissure edge + */ + class FissureNormal { - int aCurr = *anElemIter; - SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr ); - if ( !anElem ) - continue; - - vector aNodeArr( anElem->NbNodes() ); + std::vector< gp_XYZ > _normals; + bool _bothIn; + public: + void Add( const SMDS_MeshNode* n, const FissureBorder& bord ) + { + _bothIn = false; + _normals.reserve(2); + _normals.push_back( bord.GetNorm() ); + if ( _normals.size() == 2 ) + _bothIn = !isOut( n, _normals[0], bord.GetMarkedElem() ); + } + + bool IsIn( const SMDS_MeshNode* n, const SMDS_MeshElement* elem ) const + { + bool isIn = false; + switch ( _normals.size() ) { + case 1: + { + isIn = !isOut( n, _normals[0], elem ); + break; + } + case 2: + { + bool in1 = !isOut( n, _normals[0], elem ); + bool in2 = !isOut( n, _normals[1], elem ); + isIn = _bothIn ? ( in1 && in2 ) : ( in1 || in2 ); + } + } + return isIn; + } + }; + + //================================================================================ + /*! + * \brief Classify an element by a plane passing through a node + */ + //================================================================================ + + bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem ) + { + SMESH_NodeXYZ p = n; + double sumDot = 0; + for ( int i = 0, nb = elem->NbCornerNodes(); i < nb; ++i ) + { + SMESH_NodeXYZ pi = elem->GetNode( i ); + sumDot += norm * ( pi - p ); + } + return sumDot < -1e-100; + } + + //================================================================================ + /*! + * \brief Find FissureBorder's by nodes to duplicate + */ + //================================================================================ + + void findFissureBorders( const TIDSortedElemSet& theNodes, + std::vector< FissureBorder > & theFissureBorders ) + { + TIDSortedElemSet::const_iterator nIt = theNodes.begin(); + const SMDS_MeshNode* n = dynamic_cast< const SMDS_MeshNode*>( *nIt ); + if ( !n ) return; + SMDSAbs_ElementType elemType = SMDSAbs_Volume; + if ( n->NbInverseElements( elemType ) == 0 ) + { + elemType = SMDSAbs_Face; + if ( n->NbInverseElements( elemType ) == 0 ) + return; + } + // unmark elements touching the fissure + for ( ; nIt != theNodes.end(); ++nIt ) + SMESH_MeshAlgos::MarkElems( cast2Node(*nIt)->GetInverseElementIterator(), false ); + + // loop on elements touching the fissure to get their borders belonging to the fissure + std::set< FissureBorder > fissureBorders; + std::vector< const SMDS_MeshElement* > adjElems; + std::vector< const SMDS_MeshNode* > nodes; + SMDS_VolumeTool volTool; + for ( nIt = theNodes.begin(); nIt != theNodes.end(); ++nIt ) + { + SMDS_ElemIteratorPtr invIt = cast2Node(*nIt)->GetInverseElementIterator( elemType ); + while ( invIt->more() ) + { + const SMDS_MeshElement* eInv = invIt->next(); + if ( eInv->isMarked() ) continue; + eInv->setIsMarked( true ); + + if ( elemType == SMDSAbs_Volume ) + { + volTool.Set( eInv ); + int iQuad = eInv->IsQuadratic() ? 2 : 1; + for ( int iF = 0, nbF = volTool.NbFaces(); iF < nbF; ++iF ) + { + const SMDS_MeshNode** nn = volTool.GetFaceNodes( iF ); + int nbN = volTool.NbFaceNodes( iF ) / iQuad; + nodes.clear(); + bool allOnFissure = true; + for ( int iN = 0; iN < nbN && allOnFissure; iN += iQuad ) + if (( allOnFissure = theNodes.count( nn[ iN ]))) + nodes.push_back( nn[ iN ]); + if ( allOnFissure ) + fissureBorders.insert( std::move( FissureBorder( &nodes[0], nodes.size(), + elemType, adjElems ))); + } + } + else // elemType == SMDSAbs_Face + { + const SMDS_MeshNode* nn[2] = { eInv->GetNode( eInv->NbCornerNodes()-1 ), 0 }; + bool onFissure0 = theNodes.count( nn[0] ), onFissure1; + for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN; ++iN ) + { + nn[1] = eInv->GetNode( iN ); + onFissure1 = theNodes.count( nn[1] ); + if ( onFissure0 && onFissure1 ) + fissureBorders.insert( std::move( FissureBorder( nn, 2, elemType, adjElems ))); + nn[0] = nn[1]; + onFissure0 = onFissure1; + } + } + } + } + + theFissureBorders.reserve( theFissureBorders.size() + fissureBorders.size()); + std::set< FissureBorder >::iterator bord = fissureBorders.begin(); + for ( ; bord != fissureBorders.end(); ++bord ) + { + theFissureBorders.push_back( std::move( const_cast( *bord ) )); + } + return; + } // findFissureBorders() + + //================================================================================ + /*! + * \brief Find elements on one side of a fissure defined by elements or nodes to duplicate + * \param [in] theElemsOrNodes - elements or nodes to duplicate + * \param [in] theNodesNot - nodes not to duplicate + * \param [out] theAffectedElems - the found elements + */ + //================================================================================ + + void findAffectedElems( const TIDSortedElemSet& theElemsOrNodes, + TIDSortedElemSet& theAffectedElems) + { + if ( theElemsOrNodes.empty() ) return; + + // find FissureBorder's + + std::vector< FissureBorder > fissure; + std::vector< const SMDS_MeshElement* > elemsByFacet; + + TIDSortedElemSet::const_iterator elIt = theElemsOrNodes.begin(); + if ( (*elIt)->GetType() == SMDSAbs_Node ) + { + findFissureBorders( theElemsOrNodes, fissure ); + } + else + { + fissure.reserve( theElemsOrNodes.size() ); + for ( ; elIt != theElemsOrNodes.end(); ++elIt ) + fissure.push_back( std::move( FissureBorder( *elIt, elemsByFacet ))); + } + if ( fissure.empty() ) + return; + + // fill borderLinks + + TBorderLinks borderLinks; + + for ( size_t i = 0; i < fissure.size(); ++i ) + { + fissure[i].AddSelfTo( borderLinks ); + } + + // get theAffectedElems + + // unmark elements having nodes on the fissure, theAffectedElems elements will be marked + for ( size_t i = 0; i < fissure.size(); ++i ) + for ( size_t j = 0; j < fissure[i]._nodes.size(); ++j ) + { + SMESH_MeshAlgos::MarkElemNodes( fissure[i]._nodes[j]->GetInverseElementIterator(), + false, /*markElem=*/true ); + } + + std::vector facetNodes; + std::map< const SMDS_MeshNode*, FissureNormal > fissEdgeNodes2Norm; + boost::container::flat_set< const SMDS_MeshNode* > fissureNodes; + + // choose a side of fissure + fissure[0].ChooseSide(); + theAffectedElems.insert( fissure[0].GetMarkedElem() ); + + size_t nbCheckedBorders = 0; + while ( nbCheckedBorders < fissure.size() ) + { + // find a FissureBorder to treat + FissureBorder* bord = 0; + for ( size_t i = 0; i < fissure.size() && !bord; ++i ) + if ( fissure[i].GetMarkedElem() ) + bord = & fissure[i]; + for ( size_t i = 0; i < fissure.size() && !bord; ++i ) + if ( fissure[i].NbSub() > 0 && fissure[i]._elems[0] ) + { + bord = & fissure[i]; + bord->ChooseSide(); + theAffectedElems.insert( bord->GetMarkedElem() ); + } + if ( !bord ) return; + ++nbCheckedBorders; + + // treat FissureBorder's linked to bord + fissureNodes.clear(); + fissureNodes.insert( bord->_nodes.begin(), bord->_nodes.end() ); + for ( size_t i = 0; i < bord->NbSub(); ++i ) + { + TBorderLinks::iterator l2b = bord->_mappedSubs[ i ]; + if ( l2b == borderLinks.end() || l2b->second.empty() ) continue; + std::vector< FissureBorder* >& linkedBorders = l2b->second; + const SubBorder& sb = l2b->first; + const SMDS_MeshElement* bordElem = bord->GetMarkedElem(); + + if ( linkedBorders.size() == 1 ) // fissure edge reached, fill fissEdgeNodes2Norm + { + for ( int j = 0; j < sb._nbNodes; ++j ) + fissEdgeNodes2Norm[ sb._nodes[j] ].Add( sb._nodes[j], *bord ); + continue; + } + + // add to theAffectedElems elems sharing nodes of a SubBorder and a node of bordElem + // until an elem adjacent to a neighbour FissureBorder is found + facetNodes.clear(); + facetNodes.insert( facetNodes.end(), sb._nodes, sb._nodes + sb._nbNodes ); + facetNodes.resize( sb._nbNodes + 1 ); + + while ( bordElem ) + { + // check if bordElem is adjacent to a neighbour FissureBorder + for ( size_t j = 0; j < linkedBorders.size(); ++j ) + { + FissureBorder* bord2 = linkedBorders[j]; + if ( bord2 == bord ) continue; + if ( bordElem == bord2->_elems[0] || bordElem == bord2->_elems[1] ) + bordElem = 0; + else + fissureNodes.insert( bord2->_nodes.begin(), bord2->_nodes.end() ); + } + if ( !bordElem ) + break; + + // find the next bordElem + const SMDS_MeshElement* nextBordElem = 0; + for ( int iN = 0, nbN = bordElem->NbCornerNodes(); iN < nbN && !nextBordElem; ++iN ) + { + const SMDS_MeshNode* n = bordElem->GetNode( iN ); + if ( fissureNodes.count( n )) continue; + + facetNodes[ sb._nbNodes ] = n; + elemsByFacet.clear(); + if ( SMDS_Mesh::GetElementsByNodes( facetNodes, elemsByFacet ) > 1 ) + { + for ( size_t iE = 0; iE < elemsByFacet.size(); ++iE ) + if ( elemsByFacet[ iE ] != bordElem && + !elemsByFacet[ iE ]->isMarked() ) + { + theAffectedElems.insert( elemsByFacet[ iE ]); + elemsByFacet[ iE ]->setIsMarked( true ); + if ( elemsByFacet[ iE ]->GetType() == bordElem->GetType() ) + nextBordElem = elemsByFacet[ iE ]; + } + } + } + bordElem = nextBordElem; + + } // while ( bordElem ) + + linkedBorders.clear(); // not to treat this link any more + + } // loop on SubBorder's of a FissureBorder + + bord->Clear(); + + } // loop on FissureBorder's + + + // add elements sharing only one node of the fissure, except those sharing fissure edge nodes + + // mark nodes of theAffectedElems + SMESH_MeshAlgos::MarkElemNodes( theAffectedElems.begin(), theAffectedElems.end(), true ); + + // unmark nodes of the fissure + elIt = theElemsOrNodes.begin(); + if ( (*elIt)->GetType() == SMDSAbs_Node ) + SMESH_MeshAlgos::MarkElems( elIt, theElemsOrNodes.end(), false ); + else + SMESH_MeshAlgos::MarkElemNodes( elIt, theElemsOrNodes.end(), false ); + + std::vector< gp_XYZ > normVec; + + // loop on nodes of the fissure, add elements having marked nodes + for ( elIt = theElemsOrNodes.begin(); elIt != theElemsOrNodes.end(); ++elIt ) + { + const SMDS_MeshElement* e = (*elIt); + if ( e->GetType() != SMDSAbs_Node ) + e->setIsMarked( true ); // avoid adding a fissure element + + for ( int iN = 0, nbN = e->NbCornerNodes(); iN < nbN; ++iN ) + { + const SMDS_MeshNode* n = e->GetNode( iN ); + if ( fissEdgeNodes2Norm.count( n )) + continue; + + SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(); + while ( invIt->more() ) + { + const SMDS_MeshElement* eInv = invIt->next(); + if ( eInv->isMarked() ) continue; + eInv->setIsMarked( true ); + + SMDS_ElemIteratorPtr nIt = eInv->nodesIterator(); + while( nIt->more() ) + if ( nIt->next()->isMarked()) + { + theAffectedElems.insert( eInv ); + SMESH_MeshAlgos::MarkElems( eInv->nodesIterator(), true ); + n->setIsMarked( false ); + break; + } + } + } + } + + // add elements on the fissure edge + std::map< const SMDS_MeshNode*, FissureNormal >::iterator n2N; + for ( n2N = fissEdgeNodes2Norm.begin(); n2N != fissEdgeNodes2Norm.end(); ++n2N ) + { + const SMDS_MeshNode* edgeNode = n2N->first; + const FissureNormal & normals = n2N->second; + + SMDS_ElemIteratorPtr invIt = edgeNode->GetInverseElementIterator(); + while ( invIt->more() ) + { + const SMDS_MeshElement* eInv = invIt->next(); + if ( eInv->isMarked() ) continue; + eInv->setIsMarked( true ); + + // classify eInv using normals + bool toAdd = normals.IsIn( edgeNode, eInv ); + if ( toAdd ) // check if all nodes lie on the fissure edge + { + bool notOnEdge = false; + for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN && !notOnEdge; ++iN ) + notOnEdge = !fissEdgeNodes2Norm.count( eInv->GetNode( iN )); + toAdd = notOnEdge; + } + if ( toAdd ) + { + theAffectedElems.insert( eInv ); + } + } + } + + return; + } // findAffectedElems() +} // namespace + +//================================================================================ +/*! + * \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 = SMDSAbs_All; + SMDS_ElemIteratorPtr elemIt; + 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]; + elemIt = mesh->elementsIterator( type ); + break; + } + } + else + { + type = (*theElements.begin())->GetType(); + elemIt = SMESHUtils::elemSetIterator( theElements ); + } + + // un-mark all elements to avoid duplicating just created elements + SMESH_MeshAlgos::MarkElems( mesh->elementsIterator( type ), false ); + + // duplicate elements + + ElemFeatures elemType; + + vector< const SMDS_MeshNode* > nodes; + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if ( elem->GetType() != type || elem->isMarked() ) + continue; + + elemType.Init( elem, /*basicOnly=*/false ); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); + + if ( const SMDS_MeshElement* newElem = AddElement( nodes, elemType )) + newElem->setIsMarked( true ); + } +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theElems - the list of elements (edges or faces) to be replicated + The nodes for duplication could be found from these elements + \param theNodesNot - list of nodes to NOT replicate + \param theAffectedElems - the list of elements (cells and edges) to which the + replicated nodes should be associated to. + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TIDSortedElemSet& theAffectedElems ) +{ + ClearLastCreated(); + + if ( theElems.size() == 0 ) + return false; + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + if ( !aMeshDS ) + return false; + + bool res = false; + TNodeNodeMap anOldNodeToNewNode; + // duplicate elements and nodes + res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true ); + // replce nodes by duplications + res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false ); + return res; +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theMeshDS - mesh instance + \param theElems - the elements replicated or modified (nodes should be changed) + \param theNodesNot - nodes to NOT replicate + \param theNodeNodeMap - relation of old node to new created node + \param theIsDoubleElem - flag os to replicate element or modify + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + TNodeNodeMap& theNodeNodeMap, + const bool theIsDoubleElem ) +{ + // 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 ) + { + const SMDS_MeshElement* anElem = *elemItr; + // if (!anElem) + // continue; + + // duplicate nodes to duplicate element + 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(); - if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) + const SMDS_MeshNode* aCurrNode = static_cast( anIter->next() ); + const SMDS_MeshNode* aNewNode = aCurrNode; + TNodeNodeMap::iterator n2n = theNodeNodeMap.find( aCurrNode ); + if ( n2n != theNodeNodeMap.end() ) { - const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ]; - aNodeArr[ ind++ ] = aNewNode; + aNewNode = n2n->second; } - else - aNodeArr[ ind++ ] = aCurrNode; + else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode )) + { + // duplicate node + aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); + copyPosition( aCurrNode, aNewNode ); + theNodeNodeMap[ aCurrNode ] = aNewNode; + myLastCreatedNodes.push_back( aNewNode ); + } + isDuplicate |= (aCurrNode != aNewNode); + newNodes[ ind++ ] = aNewNode; + } + if ( !isDuplicate ) + continue; + + if ( theIsDoubleElem ) + AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false )); + else + theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() ); + + res = true; + } + return res; +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theNodes - identifiers of nodes to be doubled + \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, + const std::list< int >& theListOfModifiedElems ) +{ + ClearLastCreated(); + + if ( theListOfNodes.size() == 0 ) + return false; + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + if ( !aMeshDS ) + return false; + + // iterate through nodes and duplicate them + + std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + + std::list< int >::const_iterator aNodeIter; + for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter ) + { + const SMDS_MeshNode* aNode = aMeshDS->FindNode( *aNodeIter ); + if ( !aNode ) + continue; + + // duplicate node + + const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); + if ( aNewNode ) + { + copyPosition( aNode, aNewNode ); + anOldNodeToNewNode[ aNode ] = aNewNode; + myLastCreatedNodes.push_back( aNewNode ); } - anElemToNodes[ anElem ] = aNodeArr; } // Change nodes of elements - std::map< SMDS_MeshElement*, vector >::iterator - anElemToNodesIter = anElemToNodes.begin(); - for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter ) + std::vector aNodeArr; + + std::list< int >::const_iterator anElemIter; + for ( anElemIter = theListOfModifiedElems.begin(); + anElemIter != theListOfModifiedElems.end(); + anElemIter++ ) { - const SMDS_MeshElement* anElem = anElemToNodesIter->first; - vector aNodeArr = anElemToNodesIter->second; - if ( anElem ) - { - MESSAGE("ChangeElementNodes"); - aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() ); - } + const SMDS_MeshElement* anElem = aMeshDS->FindElement( *anElemIter ); + if ( !anElem ) + continue; + + aNodeArr.assign( anElem->begin_nodes(), anElem->end_nodes() ); + for( size_t i = 0; i < aNodeArr.size(); ++i ) + { + std::map< const SMDS_MeshNode*, const SMDS_MeshNode* >::iterator n2n = + anOldNodeToNewNode.find( aNodeArr[ i ]); + if ( n2n != anOldNodeToNewNode.end() ) + aNodeArr[ i ] = n2n->second; + } + aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], aNodeArr.size() ); } return true; @@ -10650,8 +11143,8 @@ namespace { //================================================================================ /*! - \brief Check if element located inside shape - \return TRUE if IN or ON shape, FALSE otherwise + \brief Check if element located inside shape + \return TRUE if IN or ON shape, FALSE otherwise */ //================================================================================ @@ -10661,9 +11154,8 @@ namespace { const double theTol) { gp_XYZ centerXYZ (0, 0, 0); - SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator(); - while (aNodeItr->more()) - centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next())); + for ( SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator(); aNodeItr->more(); ) + centerXYZ += SMESH_NodeXYZ( aNodeItr->next() ); gp_Pnt aPnt = centerXYZ / theElem->NbNodes(); theClassifier.Perform(aPnt, theTol); @@ -10718,9 +11210,9 @@ namespace { (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 + \return true \sa DoubleNodeElemGroupsInRegion() - */ +*/ //================================================================================ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems, @@ -10730,101 +11222,7 @@ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theEl { 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); - } - } + findAffectedElems( theElems, theAffectedElems ); } else { @@ -10843,29 +11241,23 @@ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theEl // 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 ) + for ( ; elemItr != theElems.end(); ++elemItr ) { - MESSAGE("element " << ielem++); - SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; - if (!anElem) - continue; + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; 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 ))) + ( bsc3d.get() ? + isInside( curElem, *bsc3d, aTol ) : + isInside( curElem, *aFaceClassifier, aTol ))) theAffectedElems.insert( curElem ); } } @@ -10894,16 +11286,16 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, return false; const double aTol = Precision::Confusion(); - auto_ptr< BRepClass3d_SolidClassifier> bsc3d; - auto_ptr<_FaceClassifier> aFaceClassifier; + SMESHUtils::Deleter< BRepClass3d_SolidClassifier> bsc3d; + SMESHUtils::Deleter<_FaceClassifier> aFaceClassifier; if ( theShape.ShapeType() == TopAbs_SOLID ) { - bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; + bsc3d._obj = new BRepClass3d_SolidClassifier( theShape ); bsc3d->PerformInfinitePoint(aTol); } else if (theShape.ShapeType() == TopAbs_FACE ) { - aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + aFaceClassifier._obj = new _FaceClassifier( TopoDS::Face( theShape )); } // iterates on indicated elements and get elements by back references from their nodes @@ -10926,7 +11318,7 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, { const SMDS_MeshElement* curElem = backElemItr->next(); if ( curElem && theElems.find(curElem) == theElems.end() && - ( bsc3d.get() ? + ( bsc3d ? isInside( curElem, *bsc3d, aTol ) : isInside( curElem, *aFaceClassifier, aTol ))) anAffected.insert( curElem ); @@ -10946,10 +11338,6 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, */ double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2) { -// MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z()); -// MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z()); -// MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z()); -// MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z()); gp_Vec vref(p0, p1); gp_Vec v1(p0, g1); gp_Vec v2(p0, g2); @@ -10984,14 +11372,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectormyMesh->GetMeshDS(); meshDS->BuildDownWardConnectivity(true); CHRONO(50); - SMDS_UnstructuredGrid *grid = meshDS->getGrid(); + SMDS_UnstructuredGrid *grid = meshDS->GetGrid(); // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes // build the list of cells with only a node or an edge on the border, with their domain and volume indexes @@ -11009,7 +11397,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector emptySet; emptyMap.clear(); - 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 his domain. + // --- build a map (face to duplicate --> 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 his domain. - MESSAGE("... Neighbors of domain #" << idom); - const TIDSortedElemSet& domain = theElems[idom]; - TIDSortedElemSet::const_iterator elemItr = domain.begin(); - for (; elemItr != domain.end(); ++elemItr) + //MESSAGE("... Neighbors of domain #" << idom); + const TIDSortedElemSet& domain = theElems[idom]; + TIDSortedElemSet::const_iterator elemItr = domain.begin(); + for (; elemItr != domain.end(); ++elemItr) + { + const SMDS_MeshElement* anElem = *elemItr; + if (!anElem) + continue; + int vtkId = anElem->GetVtkID(); + //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID()); + 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++) + { + int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared { - const SMDS_MeshElement* anElem = *elemItr; - if (!anElem) - continue; - int vtkId = anElem->getVtkId(); - //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID()); - 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++) + bool ok = false; + for ( size_t 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)) { - int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]); - const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); - if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared - { - 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 ) - { - theRestDomElems.insert( elem ); - faceDomains[face][iRestDom] = neighborsVtkIds[n]; - celldom[neighborsVtkIds[n]] = iRestDom; - } - } - } + faceDomains[face][idom] = vtkId; // volume associated to face in this domain + celldom[vtkId] = idom; + //MESSAGE(" cell with a border " << vtkId << " domain " << idom); + } + if ( !ok ) + { + theRestDomElems.insert( elem ); + faceDomains[face][iRestDom] = neighborsVtkIds[n]; + celldom[neighborsVtkIds[n]] = iRestDom; } + } } + } } + } //MESSAGE("Number of shared faces " << faceDomains.size()); std::map, DownIdCompare>::iterator itface; @@ -11104,48 +11493,48 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& 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); + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + //MESSAGE(" node " << oldId); + vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); + for (int i=0; i& domvol = itface->second; - if (!domvol.count(idomain)) + int vtkId = l.cells[i]; + const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->FromVtkToSmds(vtkId)); + if (!domain.count(anElem)) continue; - DownIdType face = itface->first; - //MESSAGE(" --- face " << face.cellId); - std::set oldNodes; - oldNodes.clear(); - grid->GetNodeIds(oldNodes, face.cellId, face.cellType); - std::set::iterator itn = oldNodes.begin(); - for (; itn != oldNodes.end(); ++itn) - { - int oldId = *itn; - //MESSAGE(" node " << oldId); - vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); - for (int i=0; iFindElement(GetMeshDS()->fromVtkToSmds(vtkId)); - if (!domain.count(anElem)) - continue; - int vtkType = grid->GetCellType(vtkId); - int downId = grid->CellIdToDownId(vtkId); - if (downId < 0) - { - MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem"); - continue; // not OK at this stage of the algorithm: - //no cells created after BuildDownWardConnectivity - } - DownIdType aCell(downId, vtkType); - cellDomains[aCell][idomain] = vtkId; - celldom[vtkId] = idomain; - //MESSAGE(" cell " << vtkId << " domain " << idomain); - } - } + int vtkType = grid->GetCellType(vtkId); + int downId = grid->CellIdToDownId(vtkId); + if (downId < 0) + { + MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem"); + continue; // not OK at this stage of the algorithm: + //no cells created after BuildDownWardConnectivity + } + DownIdType aCell(downId, vtkType); + cellDomains[aCell][idomain] = vtkId; + celldom[vtkId] = idomain; + //MESSAGE(" cell " << vtkId << " domain " << idomain); } + } } + } // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way // for each shared face, get the nodes @@ -11159,187 +11548,192 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector > 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) - MESSAGE(".. Duplication of the nodes"); + //MESSAGE(".. Duplication of the nodes"); for (int idomain = idom0; idomain < nbDomains; idomain++) + { + itface = faceDomains.begin(); + for (; itface != faceDomains.end(); ++itface) { - itface = faceDomains.begin(); - for (; itface != faceDomains.end(); ++itface) + const std::map& 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); + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (nodeDomains[oldId].empty()) { - const std::map& 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); - std::set::iterator itn = oldNodes.begin(); - for (; itn != oldNodes.end(); ++itn) + 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; + //MESSAGE(" domain " << idom); + if (!nodeDomains[oldId].count(idom)) // --- node to clone + { + if (nodeDomains[oldId].size() >= 2) // a multiple node { - int oldId = *itn; - if (nodeDomains[oldId].empty()) - { - 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; - //MESSAGE(" domain " << idom); - if (!nodeDomains[oldId].count(idom)) // --- node to clone - { - if (nodeDomains[oldId].size() >= 2) // a multiple node - { - vector orderedDoms; - //MESSAGE("multiple node " << oldId); - if (mutipleNodes.count(oldId)) - orderedDoms = mutipleNodes[oldId]; - else - { - map::iterator it = nodeDomains[oldId].begin(); - for (; it != nodeDomains[oldId].end(); ++it) - orderedDoms.push_back(it->first); - } - orderedDoms.push_back(idom); // TODO order ==> push_front or back - //stringstream txt; - //for (int i=0; iGetPoint(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("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" < orderedDoms; + //MESSAGE("multiple node " << oldId); + if (mutipleNodes.count(oldId)) + orderedDoms = mutipleNodes[oldId]; + else + { + map::iterator it = nodeDomains[oldId].begin(); + for (; it != nodeDomains[oldId].end(); ++it) + orderedDoms.push_back(it->first); + } + orderedDoms.push_back(idom); // TODO order ==> push_front or back + //stringstream txt; + //for (int i=0; iGetPoint(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("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" < domvol = itface->second; + if (!domvol.count(idomain)) + continue; + DownIdType face = itface->first; + //MESSAGE(" --- face " << face.cellId); + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + int nbMultipleNodes = 0; + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (mutipleNodes.count(oldId)) + nbMultipleNodes++; + } + if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains + { + //MESSAGE("multiple Nodes detected on a shared face"); + int downId = itface->first.cellId; + unsigned char cellType = itface->first.cellType; + // --- shared edge or shared face ? + if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces) { - std::map 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 + int nodes[3]; + int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes); + for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1 + if (mutipleNodes.count(nodes[i])) + if (!mutipleNodesToFace.count(nodes[i])) + mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]]; + } + else // shared face (between two volumes) + { + int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId); + const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId); + const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId); + for (int ie =0; ie < nbEdges; ie++) + { + int nodes[3]; + int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes); + if ( mutipleNodes.count(nodes[0]) && mutipleNodes.count( nodes[ nbNodes-1 ])) { - //MESSAGE("multiple Nodes detected on a shared face"); - int downId = itface->first.cellId; - unsigned char cellType = itface->first.cellType; - // --- shared edge or shared face ? - if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces) - { - int nodes[3]; - int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes); - for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1 - if (mutipleNodes.count(nodes[i])) - if (!mutipleNodesToFace.count(nodes[i])) - mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]]; - } - else // shared face (between two volumes) + vector vn0 = mutipleNodes[nodes[0]]; + vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; + vector doms; + for ( size_t i0 = 0; i0 < vn0.size(); i0++ ) + for ( size_t 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]); + gp_Pnt p0(coords[0], coords[1], coords[2]); + coords = grid->GetPoint(nodes[nbNodes - 1]); + gp_Pnt p1(coords[0], coords[1], coords[2]); + gp_Pnt gref; + int vtkVolIds[1000]; // an edge can belong to a lot of volumes + map domvol; // domain --> a volume with the edge + map angleDom; // oriented angles between planes defined by edge and volume centers + int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]); + for ( size_t id = 0; id < doms.size(); id++ ) { - int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId); - const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId); - const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId); - for (int ie =0; ie < nbEdges; ie++) + int idom = doms[id]; + const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom]; + for ( int ivol = 0; ivol < nbvol; ivol++ ) + { + int smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if (domain.count(elem)) { - int nodes[3]; - int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes); - if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1])) - { - vector vn0 = mutipleNodes[nodes[0]]; - vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; - vector doms; - for (int i0 = 0; i0 < vn0.size(); i0++) - for (int i1 = 0; i1 < vn1.size(); i1++) - if (vn0[i0] == vn1[i1]) - doms.push_back(vn0[i0]); - if (doms.size() >2) - { - //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]); - double *coords = grid->GetPoint(nodes[0]); - gp_Pnt p0(coords[0], coords[1], coords[2]); - coords = grid->GetPoint(nodes[nbNodes - 1]); - gp_Pnt p1(coords[0], coords[1], coords[2]); - gp_Pnt gref; - int vtkVolIds[1000]; // an edge can belong to a lot of volumes - map domvol; // domain --> a volume with the edge - map angleDom; // oriented angles between planes defined by edge and volume centers - int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]); - for (int id=0; id < doms.size(); 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 (domain.count(elem)) - { - SMDS_VtkVolume* svol = dynamic_cast(elem); - domvol[idom] = svol; - //MESSAGE(" domain " << idom << " volume " << elem->GetID()); - double values[3]; - vtkIdType npts = 0; - vtkIdType* pts = 0; - grid->GetCellPoints(vtkVolIds[ivol], npts, pts); - SMDS_VtkVolume::gravityCenter(grid, pts, npts, values); - if (id ==0) - { - gref.SetXYZ(gp_XYZ(values[0], values[1], values[2])); - angleDom[idom] = 0; - } - else - { - gp_Pnt g(values[0], values[1], values[2]); - angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pisecond << " angle " << ib->first); - } - for (int ino = 0; ino < nbNodes; ino++) - vnodes.push_back(nodes[ino]); - edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains - } - } + const SMDS_MeshVolume* svol = SMDS_Mesh::DownCast(elem); + domvol[idom] = (SMDS_MeshVolume*) svol; + //MESSAGE(" domain " << idom << " volume " << elem->GetID()); + double values[3] = { 0,0,0 }; + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(vtkVolIds[ivol], npts, pts); + for ( vtkIdType i = 0; i < npts; ++i ) + { + double *coords = grid->GetPoint( pts[i] ); + for ( int j = 0; j < 3; ++j ) + values[j] += coords[j] / npts; + } + if ( id == 0 ) + { + gref.SetCoord( values[0], values[1], values[2] ); + angleDom[idom] = 0; + } + else + { + gp_Pnt g( values[0], values[1], values[2] ); + angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pisecond << " angle " << ib->first); } + for (int ino = 0; ino < nbNodes; ino++) + vnodes.push_back(nodes[ino]); + edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains + } } + } } + } } + } // --- iterate on shared faces (volumes to modify, face to extrude) // get node id's of the face (id SMDS = id VTK) @@ -11351,119 +11745,119 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector > nodeQuadDomains; std::map mapOfJunctionGroups; - MESSAGE(".. Creation of elements: simple junction"); + //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) - { - DownIdType face = itface->first; - std::set oldNodes; - std::set::iterator itn; - oldNodes.clear(); - grid->GetNodeIds(oldNodes, face.cellId, face.cellType); - - std::map domvol = itface->second; - std::map::iterator itdom = domvol.begin(); - int dom1 = itdom->first; - int vtkVolId = itdom->second; - itdom++; - int dom2 = itdom->first; - SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, - nodeQuadDomains); - stringstream grpname; - grpname << "j_"; - if (dom1 < dom2) - grpname << dom1 << "_" << dom2; - else - grpname << dom2 << "_" << dom1; - string namegrp = grpname.str(); - if (!mapOfJunctionGroups.count(namegrp)) - mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg); - SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); - if (sgrp) - sgrp->Add(vol->GetID()); - if (vol->GetType() == SMDSAbs_Volume) - joints3DGrp->Add(vol->GetID()); - else if (vol->GetType() == SMDSAbs_Face) - joints2DGrp->Add(vol->GetID()); - } + { + 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) + { + DownIdType face = itface->first; + std::set oldNodes; + std::set::iterator itn; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); + int dom1 = itdom->first; + int vtkVolId = itdom->second; + itdom++; + int dom2 = itdom->first; + SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, + nodeQuadDomains); + stringstream grpname; + grpname << "j_"; + if (dom1 < dom2) + grpname << dom1 << "_" << dom2; + else + grpname << dom2 << "_" << dom1; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(vol->GetID()); + if (vol->GetType() == SMDSAbs_Volume) + joints3DGrp->Add(vol->GetID()); + else if (vol->GetType() == SMDSAbs_Face) + joints2DGrp->Add(vol->GetID()); } + } // --- create volumes on multiple domain intersection if requested // iterate on mutipleNodesToFace // iterate on edgesMultiDomains - MESSAGE(".. Creation of elements: multiple junction"); + //MESSAGE(".. Creation of elements: multiple junction"); if (createJointElems) + { + // --- iterate on mutipleNodesToFace + + std::map >::iterator itn = mutipleNodesToFace.begin(); + for (; itn != mutipleNodesToFace.end(); ++itn) { - // --- iterate on mutipleNodesToFace + int node = itn->first; + vector orderDom = itn->second; + vector orderedNodes; + for ( size_t idom = 0; idom < orderDom.size(); idom++ ) + orderedNodes.push_back( nodeDomains[ node ][ orderDom[ idom ]]); + SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes); - std::map >::iterator itn = mutipleNodesToFace.begin(); - for (; itn != mutipleNodesToFace.end(); ++itn) - { - int node = itn->first; - vector orderDom = itn->second; - vector orderedNodes; - for (int idom = 0; idom GetMeshDS()->AddFaceFromVtkIds(orderedNodes); - - stringstream grpname; - grpname << "m2j_"; - grpname << 0 << "_" << 0; - int idg; - string namegrp = grpname.str(); - if (!mapOfJunctionGroups.count(namegrp)) - mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg); - SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); - if (sgrp) - sgrp->Add(face->GetID()); - } - - // --- iterate on edgesMultiDomains - - std::map, std::vector >::iterator ite = edgesMultiDomains.begin(); - for (; ite != edgesMultiDomains.end(); ++ite) - { - vector nodes = ite->first; - vector orderDom = ite->second; - vector orderedNodes; - if (nodes.size() == 2) - { - //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]); - for (int ino=0; ino < nodes.size(); ino++) - if (orderDom.size() == 3) - for (int idom = 0; idom =0; idom--) - orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] ); - SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes); - - int idg; - 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()); - if (sgrp) - sgrp->Add(vol->GetID()); - } + stringstream grpname; + grpname << "m2j_"; + grpname << 0 << "_" << 0; + int idg; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(face->GetID()); + } + + // --- iterate on edgesMultiDomains + + std::map, std::vector >::iterator ite = edgesMultiDomains.begin(); + for (; ite != edgesMultiDomains.end(); ++ite) + { + vector nodes = ite->first; + vector orderDom = ite->second; + vector orderedNodes; + if (nodes.size() == 2) + { + //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]); + for ( size_t ino = 0; ino < nodes.size(); ino++ ) + if ( orderDom.size() == 3 ) + for ( size_t idom = 0; idom < orderDom.size(); idom++ ) + orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]); else - { - INFOS("Quadratic multiple joints not implemented"); - // TODO quadratic nodes - } - } + for (int idom = orderDom.size()-1; idom >=0; idom--) + orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]); + SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes); + + int idg; + 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()); + if (sgrp) + sgrp->Add(vol->GetID()); + } + else + { + //INFOS("Quadratic multiple joints not implemented"); + // TODO quadratic nodes + } } + } // --- list the explicit faces and edges of the mesh that need to be modified, // i.e. faces and edges built with one or more duplicated nodes. @@ -11475,38 +11869,38 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector >::const_iterator itnod = nodeDomains.begin(); + for (; itnod != nodeDomains.end(); ++itnod) { - std::map >::const_iterator itnod = nodeDomains.begin(); - for (; itnod != nodeDomains.end(); ++itnod) - { - int oldId = itnod->first; - //MESSAGE(" node " << oldId); - vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); - for (int i = 0; i < l.ncells; i++) + int oldId = itnod->first; + //MESSAGE(" node " << oldId); + vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); + for (int i = 0; i < l.ncells; i++) + { + int vtkId = l.cells[i]; + int vtkType = grid->GetCellType(vtkId); + int downId = grid->CellIdToDownId(vtkId); + if (downId < 0) + continue; // new cells: not to be modified + DownIdType aCell(downId, vtkType); + int volParents[1000]; + int nbvol = grid->GetParentVolumes(volParents, vtkId); + for (int j = 0; j < nbvol; j++) + if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain)) + if (!feDom.count(vtkId)) { - int vtkId = l.cells[i]; - int vtkType = grid->GetCellType(vtkId); - int downId = grid->CellIdToDownId(vtkId); - if (downId < 0) - continue; // new cells: not to be modified - DownIdType aCell(downId, vtkType); - int volParents[1000]; - int nbvol = grid->GetParentVolumes(volParents, vtkId); - for (int j = 0; j < nbvol; j++) - if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain)) - if (!feDom.count(vtkId)) - { - feDom[vtkId] = idomain; - faceOrEdgeDom[aCell] = emptyMap; - faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only - //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain - // << " type " << vtkType << " downId " << downId); - } + feDom[vtkId] = idomain; + faceOrEdgeDom[aCell] = emptyMap; + faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only + //MESSAGE("affect cell " << this->GetMeshDS()->FromVtkToSmds(vtkId) << " domain " << idomain + // << " type " << vtkType << " downId " << downId); } - } + } } + } // --- iterate on shared faces (volumes to modify, face to extrude) // get node id's of the face @@ -11514,40 +11908,40 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom}; for (int m=0; m<3; m++) - { - std::map, DownIdCompare>* amap = maps[m]; - itface = (*amap).begin(); - for (; itface != (*amap).end(); ++itface) + { + std::map, DownIdCompare>* amap = maps[m]; + itface = (*amap).begin(); + for (; itface != (*amap).end(); ++itface) + { + DownIdType face = itface->first; + std::set oldNodes; + std::set::iterator itn; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType)); + std::map localClonedNodeIds; + + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); + for (; itdom != domvol.end(); ++itdom) + { + int idom = itdom->first; + int vtkVolId = itdom->second; + //MESSAGE("modify nodes of cell " << this->GetMeshDS()->FromVtkToSmds(vtkVolId) << " domain " << idom); + localClonedNodeIds.clear(); + for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn) { - DownIdType face = itface->first; - std::set oldNodes; - std::set::iterator itn; - oldNodes.clear(); - grid->GetNodeIds(oldNodes, face.cellId, face.cellType); - //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType)); - std::map localClonedNodeIds; - - std::map domvol = itface->second; - std::map::iterator itdom = domvol.begin(); - for (; itdom != domvol.end(); ++itdom) - { - int idom = itdom->first; - int vtkVolId = itdom->second; - //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom); - localClonedNodeIds.clear(); - for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn) - { - int oldId = *itn; - if (nodeDomains[oldId].count(idom)) - { - localClonedNodeIds[oldId] = nodeDomains[oldId][idom]; - //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]); - } - } - meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds); - } + int oldId = *itn; + if (nodeDomains[oldId].count(idom)) + { + localClonedNodeIds[oldId] = nodeDomains[oldId][idom]; + //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]); + } } + meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds); + } } + } // Remove empty groups (issue 0022812) std::map::iterator name_group = mapOfJunctionGroups.begin(); @@ -11558,7 +11952,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorCleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory - grid->BuildLinks(); + grid->DeleteLinks(); CHRONOSTOP(50); counters::stats(); @@ -11577,9 +11971,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems) { - MESSAGE("-------------------------------------------------"); - MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups"); - MESSAGE("-------------------------------------------------"); + // MESSAGE("-------------------------------------------------"); + // MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups"); + // MESSAGE("-------------------------------------------------"); SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); @@ -11594,137 +11988,136 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector mapOfJunctionGroups; mapOfJunctionGroups.clear(); - for (int idom = 0; idom < theElems.size(); idom++) + for ( size_t idom = 0; idom < theElems.size(); idom++ ) + { + const TIDSortedElemSet& domain = theElems[idom]; + TIDSortedElemSet::const_iterator elemItr = domain.begin(); + for ( ; elemItr != domain.end(); ++elemItr ) { - const TIDSortedElemSet& domain = theElems[idom]; - TIDSortedElemSet::const_iterator elemItr = domain.begin(); - for (; elemItr != domain.end(); ++elemItr) - { - SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr; - SMDS_MeshFace* aFace = dynamic_cast (anElem); - if (!aFace) - continue; - // MESSAGE("aFace=" << aFace->GetID()); - bool isQuad = aFace->IsQuadratic(); - vector ln0, ln1, ln2, ln3, ln4; - - // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face - - SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator(); - while (nodeIt->more()) - { - const SMDS_MeshNode* node = static_cast (nodeIt->next()); - bool isMedium = isQuad && (aFace->IsMediumNode(node)); - if (isMedium) - ln2.push_back(node); - else - ln0.push_back(node); + const SMDS_MeshFace* aFace = meshDS->DownCast ( *elemItr ); + if (!aFace) + continue; + // MESSAGE("aFace=" << aFace->GetID()); + bool isQuad = aFace->IsQuadratic(); + vector ln0, ln1, ln2, ln3, ln4; - const SMDS_MeshNode* clone = 0; - if (!clonedNodes.count(node)) - { - clone = meshDS->AddNode(node->X(), node->Y(), node->Z()); - copyPosition( node, clone ); - clonedNodes[node] = clone; - } - else - clone = clonedNodes[node]; + // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face - if (isMedium) - ln3.push_back(clone); - else - ln1.push_back(clone); + SMDS_NodeIteratorPtr nodeIt = aFace->nodeIterator(); + while (nodeIt->more()) + { + const SMDS_MeshNode* node = nodeIt->next(); + bool isMedium = ( isQuad && aFace->IsMediumNode( node )); + if (isMedium) + ln2.push_back(node); + else + ln0.push_back(node); - const SMDS_MeshNode* inter = 0; - if (isQuad && (!isMedium)) - { - if (!intermediateNodes.count(node)) - { - inter = meshDS->AddNode(node->X(), node->Y(), node->Z()); - copyPosition( node, inter ); - intermediateNodes[node] = inter; - } - else - inter = intermediateNodes[node]; - ln4.push_back(inter); - } - } + const SMDS_MeshNode* clone = 0; + if (!clonedNodes.count(node)) + { + clone = meshDS->AddNode(node->X(), node->Y(), node->Z()); + copyPosition( node, clone ); + clonedNodes[node] = clone; + } + else + clone = clonedNodes[node]; - // --- extrude the face + if (isMedium) + ln3.push_back(clone); + else + ln1.push_back(clone); - vector ln; - SMDS_MeshVolume* vol = 0; - vtkIdType aType = aFace->GetVtkType(); - switch (aType) + const SMDS_MeshNode* inter = 0; + if (isQuad && (!isMedium)) + { + if (!intermediateNodes.count(node)) { - case VTK_TRIANGLE: - vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]); - // MESSAGE("vol prism " << vol->GetID()); - ln.push_back(ln1[0]); - ln.push_back(ln1[1]); - ln.push_back(ln1[2]); - break; - case VTK_QUAD: - vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]); - // MESSAGE("vol hexa " << vol->GetID()); - ln.push_back(ln1[0]); - ln.push_back(ln1[1]); - ln.push_back(ln1[2]); - ln.push_back(ln1[3]); - break; - case VTK_QUADRATIC_TRIANGLE: - vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2], - ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]); - // MESSAGE("vol quad prism " << vol->GetID()); - ln.push_back(ln1[0]); - ln.push_back(ln1[1]); - ln.push_back(ln1[2]); - ln.push_back(ln3[0]); - ln.push_back(ln3[1]); - ln.push_back(ln3[2]); - break; - case VTK_QUADRATIC_QUAD: -// vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3], -// ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3], -// ln4[0], ln4[1], ln4[2], ln4[3]); - vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3], - ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3], - ln4[0], ln4[1], ln4[2], ln4[3]); - // MESSAGE("vol quad hexa " << vol->GetID()); - ln.push_back(ln1[0]); - ln.push_back(ln1[1]); - ln.push_back(ln1[2]); - ln.push_back(ln1[3]); - ln.push_back(ln3[0]); - ln.push_back(ln3[1]); - ln.push_back(ln3[2]); - ln.push_back(ln3[3]); - break; - case VTK_POLYGON: - break; - default: - break; + inter = meshDS->AddNode(node->X(), node->Y(), node->Z()); + copyPosition( node, inter ); + intermediateNodes[node] = inter; } + else + inter = intermediateNodes[node]; + ln4.push_back(inter); + } + } - if (vol) - { - stringstream grpname; - grpname << "jf_"; - grpname << idom; - int idg; - string namegrp = grpname.str(); - if (!mapOfJunctionGroups.count(namegrp)) - mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); - SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); - if (sgrp) - sgrp->Add(vol->GetID()); - } + // --- extrude the face - // --- modify the face + vector ln; + SMDS_MeshVolume* vol = 0; + vtkIdType aType = aFace->GetVtkType(); + switch (aType) + { + case VTK_TRIANGLE: + vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]); + // MESSAGE("vol prism " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + break; + case VTK_QUAD: + vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]); + // MESSAGE("vol hexa " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + ln.push_back(ln1[3]); + break; + case VTK_QUADRATIC_TRIANGLE: + vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2], + ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]); + // MESSAGE("vol quad prism " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + ln.push_back(ln3[0]); + ln.push_back(ln3[1]); + ln.push_back(ln3[2]); + break; + case VTK_QUADRATIC_QUAD: + // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3], + // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3], + // ln4[0], ln4[1], ln4[2], ln4[3]); + vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3], + ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3], + ln4[0], ln4[1], ln4[2], ln4[3]); + // MESSAGE("vol quad hexa " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + ln.push_back(ln1[3]); + ln.push_back(ln3[0]); + ln.push_back(ln3[1]); + ln.push_back(ln3[2]); + ln.push_back(ln3[3]); + break; + case VTK_POLYGON: + break; + default: + break; + } - aFace->ChangeNodes(&ln[0], ln.size()); - } + if (vol) + { + stringstream grpname; + grpname << "jf_"; + grpname << idom; + int idg; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(vol->GetID()); + } + + // --- modify the face + + const_cast( aFace )->ChangeNodes( &ln[0], ln.size() ); } + } return true; } @@ -11734,16 +12127,16 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector& nodesCoords, +void SMESH_MeshEditor::CreateHoleSkin(double radius, + const TopoDS_Shape& theShape, + SMESH_NodeSearcher* theNodeSearcher, + const char* groupName, + std::vector& nodesCoords, std::vector >& listOfListOfNodes) { - MESSAGE("--------------------------------"); - MESSAGE("SMESH_MeshEditor::CreateHoleSkin"); - MESSAGE("--------------------------------"); + // 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, @@ -11756,28 +12149,28 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, 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; - 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 (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 @@ -11790,10 +12183,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, grpvName += "_vol"; SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg); if (!grp) - { - MESSAGE("group not created " << grpvName); - return; - } + { + MESSAGE("group not created " << grpvName); + return; + } SMESHDS_Group *sgrp = dynamic_cast(grp->GetGroupDS()); int idgs; // --- group of SMDS faces on the skin @@ -11801,10 +12194,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, grpsName += "_skin"; SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs); if (!grps) - { - MESSAGE("group not created " << grpsName); - return; - } + { + MESSAGE("group not created " << grpsName); + return; + } SMESHDS_Group *sgrps = dynamic_cast(grps->GetGroupDS()); int idgi; // --- group of SMDS faces internal (several shapes) @@ -11812,10 +12205,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, grpiName += "_internalFaces"; SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi); if (!grpi) - { - MESSAGE("group not created " << grpiName); - return; - } + { + MESSAGE("group not created " << grpiName); + return; + } SMESHDS_Group *sgrpi = dynamic_cast(grpi->GetGroupDS()); int idgei; // --- group of SMDS faces internal (several shapes) @@ -11823,17 +12216,17 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, grpeiName += "_internalEdges"; SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei); if (!grpei) - { - MESSAGE("group not created " << grpeiName); - return; - } + { + 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(); + SMDS_UnstructuredGrid* grid = meshDS->GetGrid(); // --- set of volumes detected inside @@ -11844,157 +12237,154 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, 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() ) { - 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()); - } - } + 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"); + size_t i = 0; + int k = 0; + while ( i < nodesCoords.size()-2 ) { - 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++; - } + 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; + { + //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()); - } + 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); + { + const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]); + //MESSAGE("startNode->nodeId " << nodeId); - double radius2 = radius*radius; - MESSAGE("radius2 " << radius2); + double radius2 = radius*radius; + //MESSAGE("radius2 " << radius2); - // --- volumes on start node + // --- 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; - } + 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 + // --- 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::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; i::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 ( size_t j = 0; j < gpnts.size(); j++ ) + { + double d2 = aPoint.SquareDistance( gpnts[ j ]); + if (d2 < distance2) { - double distance2 = 0; - if (mapOfNodeDistance2.count(pts[i])) - { - distance2 = mapOfNodeDistance2[pts[i]]; - MESSAGE("point " << pts[i] << " distance2 " << distance2); - } - else - { - double *coords = grid->GetPoint(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)); + break; } - setOfVolToCheck.erase(vtkId); + } + mapOfNodeDistance2[pts[i]] = distance2; + //MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]); + } + if (distance2 < radius2) + { + volInside = true; // one or more nodes inside the domain + sgrp->Add(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 @@ -12002,52 +12392,52 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, bool addedInside = true; std::set setOfVolToReCheck; while (addedInside) + { + //MESSAGE(" --------------------------- re check"); + addedInside = false; + std::set::iterator itv = setOfInsideVol.begin(); + for (; itv != setOfInsideVol.end(); ++itv) { - 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()) + 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) { - 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); + //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) @@ -12058,50 +12448,50 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, 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 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 { - 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)); - } + 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 @@ -12114,17 +12504,17 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, 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)) { - 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); + shapeIdToVtkIdSet[shapeId] = emptySet; + shapeIds.insert(shapeId); } + shapeIdToVtkIdSet[shapeId].insert(vtkId); + } std::map > shapeIdToEdges; // shapeId --> set of downward edges std::set emptyEdges; @@ -12132,124 +12522,124 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, 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; + { + int shapeId = itShape->first; + //MESSAGE(" --- Shape ID --- "<< shapeId); + shapeIdToEdges[shapeId] = emptyEdges; - 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::vector nodesEdges; - std::list order; - order.clear(); - if (nodesEdges.size() > 0) + 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 { - 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; - } - } + 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::vector nodes; - nodes.push_back(shapeId); - std::list::iterator itl = order.begin(); - for (; itl != order.end(); itl++) + 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 < (int)nodesEdges.size(); i++ ) + if (nodesEdges[i] == nodeTofind) + break; + if ( i == (int) nodesEdges.size() ) + found = false; // no follower found on back + else + { + if (i%2) // odd ==> 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 < (int)nodesEdges.size(); i++ ) + if ( nodesEdges[i] == nodeTofind ) + break; + if ( i == (int)nodesEdges.size() ) { - nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1; - MESSAGE(" ordered node " << nodes[nodes.size()-1]); + found = false; // no predecessor found on front + continue; } - listOfListOfNodes.push_back(nodes); + if (i%2) // odd ==> 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) @@ -12273,7 +12663,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()) @@ -12281,8 +12672,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)) @@ -12294,22 +12685,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 exists + } + 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 @@ -12371,45 +12767,59 @@ 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; + + vector presentBndElems; + vector missingBndElems; + vector freeFacets; + TConnectivity nodes, elemNodes; SMDS_ElemIteratorPtr eIt; if (elements.empty()) eIt = aMesh->elementsIterator(elemType); - else eIt = elemSetIterator( elements ); + else eIt = SMESHUtils::elemSetIterator( elements ); - while (eIt->more()) + while ( eIt->more() ) { const SMDS_MeshElement* elem = eIt->next(); 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, elemNodes; + presentBndElems.clear(); + missingBndElems.clear(); + freeFacets.clear(); nodes.clear(); elemNodes.clear(); if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume -------------- { - vTool.SetExternalNormal(); const SMDS_MeshElement* otherVol = 0; for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) { if ( !vTool.IsFreeFace(iface, &otherVol) && ( !aroundElements || elements.count( otherVol ))) continue; + freeFacets.push_back( iface ); + } + if ( missType == SMDSAbs_Face ) + vTool.SetExternalNormal(); + for ( size_t i = 0; i < freeFacets.size(); ++i ) + { + int iface = freeFacets[i]; const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface); - const int nbFaceNodes = vTool.NbFaceNodes (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 ( size_t i = 0; i < nbFaceNodes; i += 1+iQuad ) { - for ( int j = 0; j < nodes.size(); ++j ) - nodes[j] =nn[i+j]; + for ( size_t j = 0; j < nodes.size(); ++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 ); @@ -12453,7 +12863,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------ { avoidSet.clear(), avoidSet.insert( elem ); - elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ), + elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesIterator() ), SMDS_MeshElement::iterator() ); elemNodes.push_back( elemNodes[0] ); nodes.resize( 2 + iQuad ); @@ -12480,37 +12890,37 @@ 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 - for ( int i = 0; i < missingBndElems.size(); ++i ) + for ( size_t i = 0; i < missingBndElems.size(); ++i ) { - TConnectivity& nodes = missingBndElems[i]; - if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes, + TConnectivity& nodes = missingBndElems[ i ]; + if ( /*aroundElements && */tgtEditor.GetMeshDS()->FindElement( nodes, 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 = @@ -12530,7 +12940,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 ); } } @@ -12538,18 +12948,18 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, // 3. Copy present boundary elements // ---------------------------------- if ( toCopyExistingBoundary ) - for ( int i = 0 ; i < presentBndElems.size(); ++i ) + for ( size_t i = 0 ; i < presentBndElems.size(); ++i ) { const SMDS_MeshElement* e = presentBndElems[i]; - TConnectivity nodes( e->NbNodes() ); - for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); - presentEditor->AddElement(nodes, e->GetType(), e->IsPoly()); + tgtNodes.resize( e->NbNodes() ); + for ( inode = 0; inode < tgtNodes.size(); ++inode ) + 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 ) + for ( size_t i = 0 ; i < presentBndElems.size(); ++i ) { - presentEditor->myLastCreatedElems.Append(presentBndElems[i]); + presentEditor->myLastCreatedElems.push_back( presentBndElems[ i ]); } } // loop on given elements @@ -12560,11 +12970,11 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, if ( group ) { if ( SMESHDS_Group* g = dynamic_cast( group->GetGroupDS() )) - for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i ) - g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 )); + for ( size_t i = 0; i < tgtEditor.myLastCreatedElems.size(); ++i ) + g->SMDSGroup().Add( tgtEditor.myLastCreatedElems[ i ]); } - tgtEditor.myLastCreatedElems.Clear(); - tgtEditor2.myLastCreatedElems.Clear(); + tgtEditor.myLastCreatedElems.clear(); + tgtEditor2.myLastCreatedElems.clear(); // ----------------------- // 5. Copy given elements @@ -12572,16 +12982,16 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, if ( toCopyElements && targetMesh != myMesh ) { if (elements.empty()) eIt = aMesh->elementsIterator(elemType); - else eIt = elemSetIterator( elements ); + else eIt = SMESHUtils::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(); + tgtEditor.myLastCreatedElems.clear(); } } return nbAddedBnd; @@ -12607,7 +13017,7 @@ void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, case SMDS_TOP_FACE: { - const SMDS_FacePosition* fPos = static_cast< const SMDS_FacePosition* >( pos ); + SMDS_FacePositionPtr fPos = pos; GetMeshDS()->SetNodeOnFace( to, from->getshapeId(), fPos->GetUParameter(), fPos->GetVParameter() ); break; @@ -12615,7 +13025,7 @@ void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, 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 ); + SMDS_EdgePositionPtr ePos = pos; GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() ); break; } @@ -12628,3 +13038,559 @@ void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, default:; } } + +namespace // utils for MakePolyLine +{ + //================================================================================ + /*! + * \brief Sequence of found points and a current point data + */ + struct Path + { + std::vector< gp_XYZ > myPoints; + double myLength; + + const SMDS_MeshElement* myFace; + SMESH_NodeXYZ myNode1; // nodes of the edge the path entered myFace + SMESH_NodeXYZ myNode2; + int myNodeInd1; + int myNodeInd2; + double myDot1; + double myDot2; + + int mySrcPntInd; //!< start point index + TIDSortedElemSet myElemSet, myAvoidSet; + + Path(): myLength(0.0), myFace(0) {} + + bool SetCutAtCorner( const SMESH_NodeXYZ& cornerNode, + const SMDS_MeshElement* face, + const gp_XYZ& plnNorm, + const gp_XYZ& plnOrig ); + + void AddPoint( const gp_XYZ& p ); + + bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig ); + + bool ReachSamePoint( const Path& other ); + + static void Remove( std::vector< Path > & paths, size_t& i ); + }; + + //================================================================================ + /*! + * \brief Return true if this Path meats another + */ + //================================================================================ + + bool Path::ReachSamePoint( const Path& other ) + { + return ( mySrcPntInd != other.mySrcPntInd && + myFace == other.myFace ); + } + + //================================================================================ + /*! + * \brief Remove a path from a vector + */ + //================================================================================ + + void Path::Remove( std::vector< Path > & paths, size_t& i ) + { + if ( paths.size() > 1 ) + { + size_t j = paths.size() - 1; // last item to be removed + if ( i < j ) + { + paths[ i ].myPoints.swap( paths[ j ].myPoints ); + paths[ i ].myLength = paths[ j ].myLength; + paths[ i ].mySrcPntInd = paths[ j ].mySrcPntInd; + paths[ i ].myFace = paths[ j ].myFace; + paths[ i ].myNode1 = paths[ j ].myNode1; + paths[ i ].myNode2 = paths[ j ].myNode2; + paths[ i ].myNodeInd1 = paths[ j ].myNodeInd1; + paths[ i ].myNodeInd2 = paths[ j ].myNodeInd2; + paths[ i ].myDot1 = paths[ j ].myDot1; + paths[ i ].myDot2 = paths[ j ].myDot2; + } + } + paths.pop_back(); + if ( i > 0 ) + --i; + } + + //================================================================================ + /*! + * \brief Store a point that is at a node of a face if the face is intersected by plane. + * Return false if the node is a sole intersection point of the face and the plane + */ + //================================================================================ + + bool Path::SetCutAtCorner( const SMESH_NodeXYZ& cornerNode, + const SMDS_MeshElement* face, + const gp_XYZ& plnNorm, + const gp_XYZ& plnOrig ) + { + if ( face == myFace ) + return false; + myNodeInd1 = face->GetNodeIndex( cornerNode._node ); + myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes(); + int ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes(); + myNode1.Set( face->GetNode( ind3 )); + myNode2.Set( face->GetNode( myNodeInd2 )); + + myDot1 = plnNorm * ( myNode1 - plnOrig ); + myDot2 = plnNorm * ( myNode2 - plnOrig ); + + bool ok = ( myDot1 * myDot2 < 0 ); + if ( !ok && myDot1 * myDot2 == 0 ) + { + ok = ( myDot1 != myDot2 ); + if ( ok && myFace ) + ok = ( myFace->GetNodeIndex(( myDot1 == 0 ? myNode1 : myNode2 )._node ) < 0 ); + } + if ( ok ) + { + myFace = face; + myDot1 = 0; + AddPoint( cornerNode ); + } + return ok; + } + + //================================================================================ + /*! + * \brief Store a point and update myLength + */ + //================================================================================ + + void Path::AddPoint( const gp_XYZ& p ) + { + if ( !myPoints.empty() ) + myLength += ( p - myPoints.back() ).Modulus(); + else + myLength = 0; + myPoints.push_back( p ); + } + + //================================================================================ + /*! + * \brief Try to find the next point + * \param [in] plnNorm - cutting plane normal + * \param [in] plnOrig - cutting plane origin + */ + //================================================================================ + + bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig ) + { + int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes(); + if ( myNodeInd2 == nodeInd3 ) + nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes(); + + SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 ); + double dot3 = plnNorm * ( node3 - plnOrig ); + + if ( dot3 * myDot1 < 0. ) + { + myNode2 = node3; + myNodeInd2 = nodeInd3; + myDot2 = dot3; + } + else if ( dot3 * myDot2 < 0. ) + { + myNode1 = node3; + myNodeInd1 = nodeInd3; + myDot1 = dot3; + } + else if ( dot3 == 0. ) + { + SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig )) + return true; + return false; + } + else if ( myDot2 == 0. ) + { + SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner() + SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig )) + return true; + return false; + } + + double r = Abs( myDot1 / ( myDot2 - myDot1 )); + AddPoint( myNode1 * ( 1 - r ) + myNode2 * r ); + + myAvoidSet.clear(); + myAvoidSet.insert( myFace ); + myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node, + myElemSet, myAvoidSet, + &myNodeInd1, &myNodeInd2 ); + return myFace; + } + + //================================================================================ + /*! + * \brief Compute a path between two points of PolySegment + */ + struct PolyPathCompute + { + SMESH_MeshEditor::TListOfPolySegments& mySegments; //!< inout PolySegment's + std::vector< Path >& myPaths; //!< path of each of segments to compute + SMESH_Mesh* myMesh; + mutable std::vector< std::string > myErrors; + + PolyPathCompute( SMESH_MeshEditor::TListOfPolySegments& theSegments, + std::vector< Path >& thePaths, + SMESH_Mesh* theMesh): + mySegments( theSegments ), + myPaths( thePaths ), + myMesh( theMesh ), + myErrors( theSegments.size() ) + { + } + +#undef SMESH_CAUGHT +#define SMESH_CAUGHT myErrors[i] = + void operator() ( const int i ) const + { + SMESH_TRY; + const_cast< PolyPathCompute* >( this )->Compute( i ); + SMESH_CATCH( SMESH::returnError ); + } +#undef SMESH_CAUGHT + + //================================================================================ + /*! + * \brief Compute a path of a given segment + */ + //================================================================================ + + void Compute( const int iSeg ) + { + SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ]; + + // the cutting plane + gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ(); + gp_XYZ plnOrig = polySeg.myXYZ[1]; + + // Find paths connecting the 2 end points of polySeg + + std::vector< Path > paths; paths.reserve(10); + + // 1) initialize paths; two paths starts at each end point + + for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points + { + Path path; + path.mySrcPntInd = iP; + size_t nbPaths = paths.size(); + + if ( polySeg.myFace[ iP ]) // the end point lies on polySeg.myFace[ iP ] + { + // check coincidence of polySeg.myXYZ[ iP ] with nodes + const double tol = 1e-20; + SMESH_NodeXYZ nodes[4]; + for ( int i = 0; i < 3 && !polySeg.myNode1[ iP ]; ++i ) + { + nodes[ i ] = polySeg.myFace[ iP ]->GetNode( i ); + if (( nodes[ i ] - polySeg.myXYZ[ iP ]).SquareModulus() < tol*tol ) + polySeg.myNode1[ iP ] = nodes[ i ].Node(); + } + nodes[ 3 ] = nodes[ 0 ]; + + // check coincidence of polySeg.myXYZ[ iP ] with edges + for ( int i = 0; i < 3 && !polySeg.myNode1[ iP ]; ++i ) + { + SMDS_LinearEdge edge( nodes[i].Node(), nodes[i+1].Node() ); + if ( SMESH_MeshAlgos::GetDistance( &edge, polySeg.myXYZ[ iP ]) < tol ) + { + polySeg.myNode1[ iP ] = nodes[ i ].Node(); + polySeg.myNode2[ iP ] = nodes[ i + 1 ].Node(); + } + } + + if ( !polySeg.myNode1[ iP ] ) // polySeg.myXYZ[ iP ] is within polySeg.myFace[ iP ] + { + double dot[ 4 ]; + for ( int i = 0; i < 3; ++i ) + dot[ i ] = plnNorm * ( nodes[ i ] - plnOrig ); + dot[ 3 ] = dot[ 0 ]; + + int iCut = 0; // index of a cut edge + if ( dot[ 1 ] * dot[ 2 ] < 0. ) iCut = 1; + else if ( dot[ 2 ] * dot[ 3 ] < 0. ) iCut = 2; + + // initialize path so as if it entered the face via iCut-th edge + path.myFace = polySeg.myFace[ iP ]; + path.myNodeInd1 = iCut; + path.myNodeInd2 = iCut + 1; + path.myNode1.Set( nodes[ iCut ].Node() ); + path.myNode2.Set( nodes[ iCut + 1 ].Node() ); + path.myDot1 = dot[ iCut ]; + path.myDot2 = dot[ iCut + 1 ]; + path.myPoints.clear(); + path.AddPoint( polySeg.myXYZ[ iP ]); + paths.push_back( path ); + + path.Extend( plnNorm, plnOrig ); // to get another edge cut + path.myFace = polySeg.myFace[ iP ]; + if ( path.myDot1 == 0. ) // cut at a node + { + path.myNodeInd1 = ( iCut + 2 ) % 3; + path.myNodeInd2 = ( iCut + 3 ) % 3; + path.myNode2.Set( path.myFace->GetNode( path.myNodeInd2 )); + path.myDot2 = dot[ path.myNodeInd2 ]; + } + else + { + path.myNodeInd1 = path.myFace->GetNodeIndex( path.myNode1.Node() ); + path.myNodeInd2 = path.myFace->GetNodeIndex( path.myNode2.Node() ); + } + path.myPoints.clear(); + path.AddPoint( polySeg.myXYZ[ iP ]); + paths.push_back( path ); + } + } + + if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] ) + { + // the end point is on an edge + while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ], + polySeg.myNode2[ iP ], + path.myElemSet, + path.myAvoidSet, + &path.myNodeInd1, + &path.myNodeInd2 ))) + { + path.myNode1.Set( polySeg.myNode1[ iP ]); + path.myNode2.Set( polySeg.myNode2[ iP ]); + path.myDot1 = plnNorm * ( path.myNode1 - plnOrig ); + path.myDot2 = plnNorm * ( path.myNode2 - plnOrig ); + path.myPoints.clear(); + path.AddPoint( polySeg.myXYZ[ iP ]); + path.myAvoidSet.insert( path.myFace ); + paths.push_back( path ); + } + if ( nbPaths == paths.size() ) + throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1 + << " in a PolySegment " << iSeg ); + } + else if ( polySeg.myNode1[ iP ] ) // the end point is at a node + { + std::set nodes; + SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + path.myPoints.clear(); + if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig )) + { + if (( path.myDot1 * path.myDot2 != 0 ) || + ( nodes.insert( path.myDot1 == 0 ? path.myNode1._node : path.myNode2._node ).second )) + paths.push_back( path ); + } + } + } + + // look for a one-segment path + for ( size_t i = 0; i < nbPaths; ++i ) + for ( size_t j = nbPaths; j < paths.size(); ++j ) + if ( paths[i].myFace == paths[j].myFace ) + { + myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] ); + myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] ); + paths.clear(); + } + } + + // 2) extend paths and compose the shortest one connecting the two points + + myPaths[ iSeg ].myLength = 1e100; + + while ( paths.size() >= 2 ) + { + for ( size_t i = 0; i < paths.size(); ++i ) + { + Path& path = paths[ i ]; + if ( !path.Extend( plnNorm, plnOrig ) || // path reached a mesh boundary + path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others + { + Path::Remove( paths, i ); + continue; + } + + // join paths that reach same point + for ( size_t j = 0; j < paths.size(); ++j ) + { + if ( i != j && paths[i].ReachSamePoint( paths[j] )) + { + double distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus(); + double fullLength = ( paths[i].myLength + paths[j].myLength + distLast ); + if ( fullLength < myPaths[ iSeg ].myLength ) + { + myPaths[ iSeg ].myLength = fullLength; + std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints; + allPoints.swap( paths[i].myPoints ); + allPoints.insert( allPoints.end(), + paths[j].myPoints.rbegin(), + paths[j].myPoints.rend() ); + } + Path::Remove( paths, i ); + Path::Remove( paths, j ); + } + } + } + if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() ) + throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()")); + } + + if ( myPaths[ iSeg ].myPoints.empty() ) + throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg ); + + } // PolyPathCompute::Compute() + + }; // struct PolyPathCompute + +} // namespace + +//======================================================================= +//function : MakePolyLine +//purpose : Create a polyline consisting of 1D mesh elements each lying on a 2D element of +// the initial mesh +//======================================================================= + +void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments& theSegments, + SMESHDS_Group* theGroup, + SMESH_ElementSearcher* theSearcher) +{ + std::vector< Path > segPaths( theSegments.size() ); // path of each of segments + + SMESH_ElementSearcher* searcher = theSearcher; + SMESHUtils::Deleter delSearcher; + if ( !searcher ) + { + searcher = SMESH_MeshAlgos::GetElementSearcher( *GetMeshDS() ); + delSearcher._obj = searcher; + } + + // get cutting planes + + std::vector< bool > isVectorOK( theSegments.size(), true ); + const double planarCoef = 0.333; // plane height in planar case + + for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg ) + { + PolySegment& polySeg = theSegments[ iSeg ]; + + gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] ); + gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] ); + if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] )); + if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] )); + + polySeg.myFace[0] = polySeg.myFace[1] = 0; + if ( !polySeg.myNode1[0] && !polySeg.myNode2[0] ) + { + p1 = searcher->Project( polySeg.myXYZ[0], SMDSAbs_Face, &polySeg.myFace[0] ); + } + if ( !polySeg.myNode1[1] && !polySeg.myNode2[1] ) + { + p2 = searcher->Project( polySeg.myXYZ[1], SMDSAbs_Face, &polySeg.myFace[1] ); + } + polySeg.myXYZ[0] = p1; + polySeg.myXYZ[1] = p2; + + gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ(); + + isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits::min() ); + if ( !isVectorOK[ iSeg ]) + { + gp_XYZ pMid = 0.5 * ( p1 + p2 ); + const SMDS_MeshElement* face; + polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face ); + polySeg.myVector = polySeg.myMidProjPoint.XYZ() - pMid; + + gp_XYZ faceNorm; + SMESH_MeshAlgos::FaceNormal( face, faceNorm ); + + if ( polySeg.myVector.Magnitude() < Precision::Confusion() || + polySeg.myVector * faceNorm < Precision::Confusion() ) + { + polySeg.myVector = faceNorm; + polySeg.myMidProjPoint = pMid + faceNorm * ( p1 - p2 ).Modulus() * planarCoef; + } + } + else + { + polySeg.myVector = plnNorm ^ ( p1 - p2 ); + } + } + + // assure that inverse elements are constructed, avoid their concurrent building in threads + GetMeshDS()->nodesIterator()->next()->NbInverseElements(); + + // find paths + + PolyPathCompute algo( theSegments, segPaths, myMesh ); + OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 ); + + for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg ) + if ( !algo.myErrors[ iSeg ].empty() ) + throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() ); + + // create an 1D mesh + + const SMDS_MeshNode *n, *nPrev = 0; + SMESHDS_Mesh* mesh = GetMeshDS(); + + for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg ) + { + const Path& path = segPaths[iSeg]; + if ( path.myPoints.size() < 2 ) + continue; + + double tol = path.myLength / path.myPoints.size() / 1000.; + if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol ) + { + nPrev = mesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() ); + myLastCreatedNodes.push_back( nPrev ); + } + for ( size_t iP = 1; iP < path.myPoints.size(); ++iP ) + { + n = mesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() ); + myLastCreatedNodes.push_back( n ); + + const SMDS_MeshElement* elem = mesh->AddEdge( nPrev, n ); + myLastCreatedElems.push_back( elem ); + if ( theGroup ) + theGroup->Add( elem ); + + nPrev = n; + } + + // return a vector + + gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() ); + if ( isVectorOK[ iSeg ]) + { + // find the most distance point of a path + double maxDist = 0; + for ( size_t iP = 1; iP < path.myPoints.size(); ++iP ) + { + double dist = Abs( theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] )); + if ( dist > maxDist ) + { + maxDist = dist; + theSegments[iSeg].myMidProjPoint = path.myPoints[iP]; + } + } + if ( maxDist < Precision::Confusion() ) // planar case + theSegments[iSeg].myMidProjPoint = + pMid + theSegments[iSeg].myVector.XYZ().Normalized() * path.myLength * planarCoef; + } + theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint ); + } + + return; +}