X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=9e38d0e4c28904038030267eae2455e9e45f7b81;hp=16ed768ec1bf3b861c8dbdf905f473f4d75cacf4;hb=5e2c97c386dc03e51e072c7f9909803a86307872;hpb=973402fcd3e362eb61f1561da154817f125034e5 diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 16ed768ec..d06ce7306 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2013 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 @@ -6,7 +6,7 @@ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,30 +26,28 @@ #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" #include #include @@ -72,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -94,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 : @@ -124,18 +116,64 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) { } +//================================================================================ +/*! + * \brief Return mesh DS + */ +//================================================================================ + +SMESHDS_Mesh * SMESH_MeshEditor::GetMeshDS() +{ + return myMesh->GetMeshDS(); +} + + //================================================================================ /*! * \brief Clears myLastCreatedNodes and myLastCreatedElems */ //================================================================================ -void SMESH_MeshEditor::CrearLastCreated() +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; +} //======================================================================= /*! @@ -145,18 +183,16 @@ void SMESH_MeshEditor::CrearLastCreated() 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] ); @@ -189,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] ); @@ -284,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: @@ -306,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; } @@ -326,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() ); @@ -340,7 +391,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs else return 0; } - return AddElement( nodes, type, isPoly, ID ); + return AddElement( nodes, features ); } //======================================================================= @@ -352,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; @@ -414,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() ) @@ -449,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() ); } } } @@ -467,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() ) @@ -518,14 +563,12 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) } else { - const map& id2sm = GetMeshDS()->SubMeshes(); - map::const_iterator id_sm = id2sm.begin(); - for ( ; id_sm != id2sm.end(); ++id_sm ) - if ( id_sm->second->Contains( theElem )) - return id_sm->first; + SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes(); + while ( const SMESHDS_SubMesh* sm = smIt->next() ) + if ( sm->Contains( theElem )) + return sm->GetID(); } - //MESSAGE ("::FindShape() - SHAPE NOT FOUND") return 0; } @@ -637,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 ) |\ | // |/ | | \| @@ -658,7 +699,7 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, // put nodes in array and find out indices of the same ones const SMDS_MeshNode* aNodes [6]; - int sameInd [] = { 0, 0, 0, 0, 0, 0 }; + int sameInd [] = { -1, -1, -1, -1, -1, -1 }; int i = 0; SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); while ( it->more() ) { @@ -684,15 +725,15 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, } // find indices of 1,2 and of A,B in theTria1 - int iA = 0, iB = 0, i1 = 0, i2 = 0; + int iA = -1, iB = 0, i1 = 0, i2 = 0; for ( i = 0; i < 6; i++ ) { - if ( sameInd [ i ] == 0 ) { + if ( sameInd [ i ] == -1 ) { if ( i < 3 ) i1 = i; else i2 = i; } else if (i < 3) { - if ( iA ) iB = i; - else iA = i; + if ( iA >= 0) iB = i; + else iA = i; } } // nodes 1 and 2 should not be the same @@ -764,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 { @@ -839,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)) { @@ -962,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 ); @@ -1036,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 ); @@ -1059,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; @@ -1076,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; @@ -1101,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 ); } @@ -1120,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. */ @@ -1135,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() ); } @@ -1174,7 +1205,7 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, avoidSet.clear(); avoidSet.insert(theFace); - NLink link( theFace->GetNode( 0 ), 0 ); + NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 ); const int nbNodes = theFace->NbCornerNodes(); for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace @@ -1230,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 ) { @@ -1245,6 +1276,92 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, return nbReori; } +//================================================================================ +/*! + * \brief Reorient faces basing on orientation of adjacent volumes. + * \param theFaces - faces to reorient. If empty, all mesh faces are treated. + * \param theVolumes - reference volumes. + * \param theOutsideNormal - to orient faces to have their normal + * pointing either \a outside or \a inside the adjacent volumes. + * \return number of reoriented faces. + */ +//================================================================================ + +int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, + TIDSortedElemSet & theVolumes, + const bool theOutsideNormal) +{ + int nbReori = 0; + + SMDS_ElemIteratorPtr faceIt; + if ( theFaces.empty() ) + faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face ); + else + faceIt = SMESHUtils::elemSetIterator( theFaces ); + + vector< const SMDS_MeshNode* > faceNodes; + TIDSortedElemSet checkedVolumes; + set< const SMDS_MeshNode* > faceNodesSet; + SMDS_VolumeTool volumeTool; + + while ( faceIt->more() ) // loop on given faces + { + const SMDS_MeshElement* face = faceIt->next(); + if ( face->GetType() != SMDSAbs_Face ) + continue; + + const size_t nbCornersNodes = face->NbCornerNodes(); + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + + checkedVolumes.clear(); + SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* volume = vIt->next(); + + if ( !checkedVolumes.insert( volume ).second ) + continue; + if ( !theVolumes.empty() && !theVolumes.count( volume )) + continue; + + // is volume adjacent? + bool allNodesCommon = true; + for ( size_t iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN ) + allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 ); + if ( !allNodesCommon ) + continue; + + // get nodes of a corresponding volume facet + faceNodesSet.clear(); + faceNodesSet.insert( faceNodes.begin(), faceNodes.end() ); + volumeTool.Set( volume ); + int facetID = volumeTool.GetFaceIndex( faceNodesSet ); + if ( facetID < 0 ) continue; + volumeTool.SetExternalNormal(); + const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID ); + + // compare order of faceNodes and facetNodes + const int iQ = 1 + ( nbCornersNodes < faceNodes.size() ); + int iNN[2]; + for ( int i = 0; i < 2; ++i ) + { + const SMDS_MeshNode* n = facetNodes[ i*iQ ]; + for ( size_t iN = 0; iN < nbCornersNodes; ++iN ) + if ( faceNodes[ iN ] == n ) + { + iNN[ i ] = iN; + break; + } + } + bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1]; + if ( isOutside != theOutsideNormal ) + nbReori += Reorient( face ); + } + } // loop on given faces + + return nbReori; +} + //======================================================================= //function : getBadRate //purpose : @@ -1269,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++ ) { @@ -1348,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 ); @@ -1366,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; @@ -1437,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 ] ); @@ -1464,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 ); } } } @@ -1495,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; @@ -1603,44 +1719,110 @@ namespace const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3, thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 }; + // Methods of splitting hexahedron into prisms + + const int theHexTo4Prisms_BT[6*4+1] = // bottom-top + { + 0, 1, 8, 4, 5, 9, 1, 2, 8, 5, 6, 9, 2, 3, 8, 6, 7, 9, 3, 0, 8, 7, 4, 9, -1 + }; + const int theHexTo4Prisms_LR[6*4+1] = // left-right + { + 1, 0, 8, 2, 3, 9, 0, 4, 8, 3, 7, 9, 4, 5, 8, 7, 6, 9, 5, 1, 8, 6, 2, 9, -1 + }; + const int theHexTo4Prisms_FB[6*4+1] = // front-back + { + 0, 3, 9, 1, 2, 8, 3, 7, 9, 2, 6, 8, 7, 4, 9, 6, 5, 8, 4, 0, 9, 5, 1, 8, -1 + }; + + const int theHexTo2Prisms_BT_1[6*2+1] = + { + 0, 1, 3, 4, 5, 7, 1, 2, 3, 5, 6, 7, -1 + }; + const int theHexTo2Prisms_BT_2[6*2+1] = + { + 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7, -1 + }; + const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 }; + + const int theHexTo2Prisms_LR_1[6*2+1] = + { + 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1 + }; + const int theHexTo2Prisms_LR_2[6*2+1] = + { + 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1 + }; + const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 }; + + const int theHexTo2Prisms_FB_1[6*2+1] = + { + 0, 3, 4, 1, 2, 5, 3, 7, 4, 2, 6, 5, -1 + }; + const int theHexTo2Prisms_FB_2[6*2+1] = + { + 0, 3, 7, 1, 2, 7, 0, 7, 4, 1, 6, 5, -1 + }; + const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 }; + + struct TTriangleFacet //!< stores indices of three nodes of tetra facet { int _n1, _n2, _n3; TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {} bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); } - bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const; + bool hasAdjacentVol( const SMDS_MeshElement* elem, + const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const; }; struct TSplitMethod { - int _nbTetra; + int _nbSplits; + int _nbCorners; const int* _connectivity; //!< foursomes of tetra connectivy finished by -1 bool _baryNode; //!< additional node is to be created at cell barycenter bool _ownConn; //!< to delete _connectivity in destructor map _faceBaryNode; //!< map face index to node at BC of face TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false) - : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} + : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; } bool hasFacet( const TTriangleFacet& facet ) const { - const int* tetConn = _connectivity; - for ( ; tetConn[0] >= 0; tetConn += 4 ) - if (( facet.contains( tetConn[0] ) + - facet.contains( tetConn[1] ) + - facet.contains( tetConn[2] ) + - facet.contains( tetConn[3] )) == 3 ) - return true; + if ( _nbCorners == 4 ) + { + const int* tetConn = _connectivity; + for ( ; tetConn[0] >= 0; tetConn += 4 ) + if (( facet.contains( tetConn[0] ) + + facet.contains( tetConn[1] ) + + facet.contains( tetConn[2] ) + + facet.contains( tetConn[3] )) == 3 ) + return true; + } + else // prism, _nbCorners == 6 + { + const int* prismConn = _connectivity; + for ( ; prismConn[0] >= 0; prismConn += 6 ) + { + if (( facet.contains( prismConn[0] ) && + facet.contains( prismConn[1] ) && + facet.contains( prismConn[2] )) + || + ( facet.contains( prismConn[3] ) && + facet.contains( prismConn[4] ) && + facet.contains( prismConn[5] ))) + return true; + } + } return false; } }; //======================================================================= /*! - * \brief return TSplitMethod for the given element + * \brief return TSplitMethod for the given element to split into tetrahedra */ //======================================================================= - TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) + TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) { const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; @@ -1665,8 +1847,8 @@ namespace { TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); - if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 ); - else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 ); + if ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 ); + else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 ); } else { @@ -1679,7 +1861,7 @@ namespace TTriangleFacet t023( nInd[ iQ * ( iCom )], nInd[ iQ * ( (iCom+2)%nbNodes )], nInd[ iQ * ( (iCom+3)%nbNodes )]); - if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() )) + if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() )) { triaSplits.push_back( t012 ); triaSplits.push_back( t023 ); @@ -1714,20 +1896,21 @@ namespace break; case SMDSEntity_Penta: case SMDSEntity_Quad_Penta: + case SMDSEntity_BiQuad_Penta: connVariants = thePentaTo3; nbTet = 3; nbVariants = 6; break; default: nbVariants = 0; } - for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant ) + for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant ) { // check method compliancy with adjacent tetras, // all found splits must be among facets of tetras described by this method method = TSplitMethod( nbTet, connVariants[variant] ); - if ( hasAdjacentSplits && method._nbTetra > 0 ) + if ( hasAdjacentSplits && method._nbSplits > 0 ) { bool facetCreated = true; - for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) + 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 ) @@ -1738,7 +1921,7 @@ namespace } } } - if ( method._nbTetra < 1 ) + if ( method._nbSplits < 1 ) { // No standard method is applicable, use a generic solution: // each facet of a volume is split into triangles and @@ -1832,7 +2015,7 @@ namespace connectivity[ connSize++ ] = baryCenInd; } } - method._nbTetra += nbTet; + method._nbSplits += nbTet; } // loop on volume faces @@ -1842,13 +2025,132 @@ namespace return method; } + //======================================================================= + /*! + * \brief return TSplitMethod to split haxhedron into prisms + */ + //======================================================================= + + TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol, + const int methodFlags, + const int facetToSplit) + { + // order of facets in HEX according to SMDS_VolumeTool::Hexa_F : + // B, T, L, B, R, F + const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2] + + if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS ) + { + static TSplitMethod to4methods[4]; // order BT, LR, FB + if ( to4methods[iF]._nbSplits == 0 ) + { + switch ( iF ) { + case 0: + to4methods[iF]._connectivity = theHexTo4Prisms_BT; + to4methods[iF]._faceBaryNode[ 0 ] = 0; + to4methods[iF]._faceBaryNode[ 1 ] = 0; + break; + case 1: + to4methods[iF]._connectivity = theHexTo4Prisms_LR; + to4methods[iF]._faceBaryNode[ 2 ] = 0; + to4methods[iF]._faceBaryNode[ 4 ] = 0; + break; + case 2: + to4methods[iF]._connectivity = theHexTo4Prisms_FB; + to4methods[iF]._faceBaryNode[ 3 ] = 0; + to4methods[iF]._faceBaryNode[ 5 ] = 0; + break; + default: return to4methods[3]; + } + to4methods[iF]._nbSplits = 4; + to4methods[iF]._nbCorners = 6; + } + return to4methods[iF]; + } + // else if ( methodFlags == HEXA_TO_2_PRISMS ) + + TSplitMethod method; + + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + + const int nbVariants = 2, nbSplits = 2; + const int** connVariants = 0; + switch ( iF ) { + case 0: connVariants = theHexTo2Prisms_BT; break; + case 1: connVariants = theHexTo2Prisms_LR; break; + case 2: connVariants = theHexTo2Prisms_FB; break; + default: return method; + } + + // look for prisms adjacent via facetToSplit and an opposite one + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit; + int nbNodes = vol.NbFaceNodes( iFacet ) / iQ; + if ( nbNodes != 4 ) return method; + + const int* nInd = vol.GetFaceNodesIndices( iFacet ); + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + TTriangleFacet* t; + if ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA )) + t = &t012; + else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA )) + t = &t123; + else + continue; + + // there are adjacent prism + for ( int variant = 0; variant < nbVariants; ++variant ) + { + // check method compliancy with adjacent prisms, + // the found prism facets must be among facets of prisms described by current method + method._nbSplits = nbSplits; + method._nbCorners = 6; + method._connectivity = connVariants[ variant ]; + if ( method.hasFacet( *t )) + return method; + } + } + + // No adjacent prisms. Select a variant with a best aspect ratio. + + double badness[2] = { 0., 0. }; + static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio); + const SMDS_MeshNode** nodes = vol.GetNodes(); + for ( int variant = 0; variant < nbVariants; ++variant ) + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit; + const int* nInd = vol.GetFaceNodesIndices( iFacet ); + + method._connectivity = connVariants[ variant ]; + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123; + + SMDS_FaceOfNodes tria ( nodes[ t->_n1 ], + nodes[ t->_n2 ], + nodes[ t->_n3 ] ); + badness[ variant ] += getBadRate( &tria, aspectRatio ); + } + const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] ); + + method._nbSplits = nbSplits; + method._nbCorners = 6; + method._connectivity = connVariants[ iBetter ]; + + return method; + } + //================================================================================ /*! * \brief Check if there is a tetraherdon adjacent to the given element via this facet */ //================================================================================ - bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const + bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement* elem, + const SMDSAbs_GeometryType geom ) const { // find the tetrahedron including the three nodes of facet const SMDS_MeshNode* n1 = elem->GetNode(_n1); @@ -1858,16 +2160,16 @@ namespace while ( volIt1->more() ) { const SMDS_MeshElement* v = volIt1->next(); - SMDSAbs_EntityType type = v->GetEntityType(); - if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra ) + if ( v->GetGeomType() != geom ) continue; - if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 ) + const int lastCornerInd = v->NbCornerNodes() - 1; + if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd ) continue; // medium node not allowed const int ind2 = v->GetNodeIndex( n2 ); - if ( ind2 < 0 || 3 < ind2 ) + if ( ind2 < 0 || lastCornerInd < ind2 ) continue; const int ind3 = v->GetNodeIndex( n3 ); - if ( ind3 < 0 || 3 < ind3 ) + if ( ind3 < 0 || lastCornerInd < ind3 ) continue; return true; } @@ -1900,19 +2202,19 @@ namespace } // namespace //======================================================================= -//function : SplitVolumesIntoTetra -//purpose : Split volume elements into tetrahedra. +//function : SplitVolumes +//purpose : Split volume elements into tetrahedra or prisms. +// If facet ID < 0, element is split into tetrahedra, +// else a hexahedron is split into prisms so that the given facet is +// split into triangles //======================================================================= -void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, - const int theMethodFlags) +void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, + const int theMethodFlags) { - // std-like iterator on coordinates of nodes of mesh element - typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator; - NXyzIterator xyzEnd; - SMDS_VolumeTool volTool; - SMESH_MesherHelper helper( *GetMesh()); + SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh()); + fHelper.ToFixNodeParameters( true ); SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1); SMESHDS_SubMesh* fSubMesh = 0;//subMesh; @@ -1922,30 +2224,35 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, // map face of volume to it's baricenrtic node map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; double bc[3]; + vector splitVols; - TIDSortedElemSet::const_iterator elem = theElems.begin(); - for ( ; elem != theElems.end(); ++elem ) + TFacetOfElem::const_iterator elem2facet = theElems.begin(); + for ( ; elem2facet != theElems.end(); ++elem2facet ) { - if ( (*elem)->GetType() != SMDSAbs_Volume ) + const SMDS_MeshElement* elem = elem2facet->first; + const int facetToSplit = elem2facet->second; + if ( elem->GetType() != SMDSAbs_Volume ) continue; - SMDSAbs_EntityType geomType = (*elem)->GetEntityType(); + const SMDSAbs_EntityType geomType = elem->GetEntityType(); if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra ) continue; - if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange... + if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange... - TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags ); - if ( splitMethod._nbTetra < 1 ) continue; + TSplitMethod splitMethod = ( facetToSplit < 0 ? + getTetraSplitMethod( volTool, theMethodFlags ) : + getPrismSplitMethod( volTool, theMethodFlags, facetToSplit )); + if ( splitMethod._nbSplits < 1 ) continue; // find submesh to add new tetras to - if ( !subMesh || !subMesh->Contains( *elem )) + if ( !subMesh || !subMesh->Contains( elem )) { - int shapeID = FindShape( *elem ); + int shapeID = FindShape( elem ); helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh subMesh = GetMeshDS()->MeshElements( shapeID ); } int iQ; - if ( (*elem)->IsQuadratic() ) + if ( elem->IsQuadratic() ) { iQ = 2; // add quadratic links to the helper @@ -1963,7 +2270,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, iQ = 1; helper.SetIsQuadratic( false ); } - vector nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() ); + vector nodes( volTool.GetNodes(), + volTool.GetNodes() + elem->NbNodes() ); helper.SetElementsOnShape( true ); if ( splitMethod._baryNode ) { @@ -1971,7 +2279,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & 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() ) { @@ -1985,22 +2293,31 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & 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 tetras - vector tetras( splitMethod._nbTetra ); // splits of a volume - const int* tetConn = splitMethod._connectivity; - for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 ) - newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ], - nodes[ tetConn[1] ], - nodes[ tetConn[2] ], - nodes[ tetConn[3] ])); + // make new volumes + splitVols.resize( splitMethod._nbSplits ); // splits of a volume + const int* volConn = splitMethod._connectivity; + if ( splitMethod._nbCorners == 4 ) // tetra + for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners ) + newElems.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.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, tetras, GetMeshDS() ); + ReplaceElemInGroups( elem, splitVols, GetMeshDS() ); // Split faces on sides of the split volume @@ -2029,22 +2346,42 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, map::iterator iF_n = splitMethod._faceBaryNode.find(iF); if ( iF_n != splitMethod._faceBaryNode.end() ) { + const SMDS_MeshNode *baryNode = iF_n->second; for ( int iN = 0; iN < nbNodes*iQ; iN += iQ ) { const SMDS_MeshNode* n1 = fNodes[iN]; const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)]; - const SMDS_MeshNode *n3 = iF_n->second; + const SMDS_MeshNode *n3 = baryNode; if ( !volTool.IsFaceExternal( iF )) swap( n2, n3 ); triangles.push_back( helper.AddFace( n1,n2,n3 )); - - if ( fSubMesh && n3->getshapeId() < 1 ) - fSubMesh->AddNode( n3 ); + } + if ( fSubMesh ) // update position of the bary node on geometry + { + if ( subMesh ) + subMesh->RemoveNode( baryNode ); + GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() ); + const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() ); + if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE ) + { + fHelper.SetSubShape( s ); + gp_XY uv( 1e100, 1e100 ); + double distXYZ[4]; + if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode, + uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) && + uv.X() < 1e100 ) + { + // node is too far from the surface + GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] ); + const_cast( baryNode )->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() ))); + } + } } } else { - // 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 @@ -2069,6 +2406,8 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, } } list< TTriangleFacet >::iterator facet = facets.begin(); + if ( facet == facets.end() ) + break; for ( ; facet != facets.end(); ++facet ) { if ( !volTool.IsFaceExternal( iF )) @@ -2078,20 +2417,20 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & 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 ); - } + } // while a face based on facet nodes exists } // loop on volume faces to split them into triangles - GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false ); + GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); if ( geomType == SMDSEntity_TriQuad_Hexa ) { @@ -2107,53 +2446,427 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, } //======================================================================= -//function : AddToSameGroups -//purpose : add elemToAdd to the groups the elemInGroups belongs to +//function : GetHexaFacetsToSplit +//purpose : For hexahedra that will be split into prisms, finds facets to +// split into triangles. Only hexahedra adjacent to the one closest +// to theFacetNormal.Location() are returned. +//param [in,out] theHexas - the hexahedra +//param [in] theFacetNormal - facet normal +//param [out] theFacets - the hexahedra and found facet IDs //======================================================================= -void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, - const SMDS_MeshElement* elemInGroups, - SMESHDS_Mesh * aMesh) +void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, + const gp_Ax1& theFacetNormal, + TFacetOfElem & theFacets) { - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) { - set::const_iterator grIt = groups.begin(); - for ( ; grIt != groups.end(); grIt++ ) { - SMESHDS_Group* group = dynamic_cast( *grIt ); - if ( group && group->Contains( elemInGroups )) - group->SMDSGroup().Add( elemToAdd ); - } - } -} +#define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): " + // Find a hexa closest to the location of theFacetNormal -//======================================================================= -//function : RemoveElemFromGroups -//purpose : Remove removeelem to the groups the elemInGroups belongs to -//======================================================================= -void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem, - SMESHDS_Mesh * aMesh) -{ - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) + const SMDS_MeshElement* startHex; { - set::const_iterator GrIt = groups.begin(); - for (; GrIt != groups.end(); GrIt++) - { - SMESHDS_Group* grp = dynamic_cast(*GrIt); - if (!grp || grp->IsEmpty()) continue; - grp->SMDSGroup().Remove(removeelem); - } + // get SMDS_ElemIteratorPtr on theHexas + typedef const SMDS_MeshElement* TValue; + typedef TIDSortedElemSet::iterator TSetIterator; + typedef SMDS::SimpleAccessor TAccesor; + typedef SMDS_MeshElement::GeomFilter TFilter; + typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter; + SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr + ( new TElemSetIter( theHexas.begin(), + theHexas.end(), + SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA ))); + + SMESH_ElementSearcher* searcher = + SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt ); + + startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume ); + + delete searcher; + + if ( !startHex ) + throw SALOME_Exception( THIS_METHOD "startHex not found"); } -} -//================================================================================ -/*! - * \brief Replace elemToRm by elemToAdd in the all groups - */ -//================================================================================ + // Select a facet of startHex by theFacetNormal -void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + SMDS_VolumeTool vTool( startHex ); + double norm[3], dot, maxDot = 0; + int facetID = -1; + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] )) + { + dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] ))); + if ( dot > maxDot ) + { + facetID = iF; + maxDot = dot; + } + } + if ( facetID < 0 ) + throw SALOME_Exception( THIS_METHOD "facet of startHex not found"); + + // Fill theFacets starting from facetID of startHex + + // facets used for searching of volumes adjacent to already treated ones + typedef pair< TFacetOfElem::iterator, int > TElemFacets; + typedef map< TVolumeFaceKey, TElemFacets > TFacetMap; + TFacetMap facetsToCheck; + + set facetNodes; + const SMDS_MeshElement* curHex; + + const bool allHex = ((int) theHexas.size() == myMesh->NbHexas() ); + + while ( startHex ) + { + // move in two directions from startHex via facetID + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + curHex = startHex; + int curFacet = facetID; + if ( is2nd ) // do not treat startHex twice + { + vTool.Set( curHex ); + if ( vTool.IsFreeFace( curFacet, &curHex )) + { + curHex = 0; + } + else + { + vTool.GetFaceNodes( curFacet, facetNodes ); + vTool.Set( curHex ); + curFacet = vTool.GetFaceIndex( facetNodes ); + } + } + while ( curHex ) + { + // store a facet to split + if ( curHex->GetGeomType() != SMDSGeom_HEXA ) + { + theFacets.insert( make_pair( curHex, -1 )); + break; + } + if ( !allHex && !theHexas.count( curHex )) + break; + + pair< TFacetOfElem::iterator, bool > facetIt2isNew = + theFacets.insert( make_pair( curHex, curFacet )); + if ( !facetIt2isNew.second ) + break; + + // remember not-to-split facets in facetsToCheck + int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet ); + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + if ( iF == curFacet && iF == oppFacet ) + continue; + TVolumeFaceKey facetKey ( vTool, iF ); + TElemFacets elemFacet( facetIt2isNew.first, iF ); + pair< TFacetMap::iterator, bool > it2isnew = + facetsToCheck.insert( make_pair( facetKey, elemFacet )); + if ( !it2isnew.second ) + facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked + } + // pass to a volume adjacent via oppFacet + if ( vTool.IsFreeFace( oppFacet, &curHex )) + { + curHex = 0; + } + else + { + // get a new curFacet + vTool.GetFaceNodes( oppFacet, facetNodes ); + vTool.Set( curHex ); + curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet ); + } + } + } // move in two directions from startHex via facetID + + // Find a new startHex by facetsToCheck + + startHex = 0; + facetID = -1; + TFacetMap::iterator fIt = facetsToCheck.begin(); + while ( !startHex && fIt != facetsToCheck.end() ) + { + const TElemFacets& elemFacets = fIt->second; + const SMDS_MeshElement* hex = elemFacets.first->first; + int splitFacet = elemFacets.first->second; + int lateralFacet = elemFacets.second; + facetsToCheck.erase( fIt ); + fIt = facetsToCheck.begin(); + + vTool.Set( hex ); + if ( vTool.IsFreeFace( lateralFacet, &curHex ) || + curHex->GetGeomType() != SMDSGeom_HEXA ) + continue; + if ( !allHex && !theHexas.count( curHex )) + continue; + + startHex = curHex; + + // find a facet of startHex to split + + set lateralNodes; + vTool.GetFaceNodes( lateralFacet, lateralNodes ); + vTool.GetFaceNodes( splitFacet, facetNodes ); + int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet ); + vTool.Set( startHex ); + lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet ); + + // look for a facet of startHex having common nodes with facetNodes + // but not lateralFacet + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + if ( iF == lateralFacet ) + continue; + int nbCommonNodes = 0; + const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF ); + for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN ) + nbCommonNodes += facetNodes.count( nn[ iN ]); + + if ( nbCommonNodes >= 2 ) + { + facetID = iF; + break; + } + } + if ( facetID < 0 ) + throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found"); + } + } // while ( startHex ) + + return; +} + +namespace +{ + //================================================================================ + /*! + * \brief Selects nodes of several elements according to a given interlace + * \param [in] srcNodes - nodes to select from + * \param [out] tgtNodesVec - array of nodes of several elements to fill in + * \param [in] interlace - indices of nodes for all elements + * \param [in] nbElems - nb of elements + * \param [in] nbNodes - nb of nodes in each element + * \param [in] mesh - the mesh + * \param [out] elemQueue - a list to push elements found by the selected nodes + * \param [in] type - type of elements to look for + */ + //================================================================================ + + void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes, + vector< const SMDS_MeshNode* >* tgtNodesVec, + const int* interlace, + const int nbElems, + const int nbNodes, + SMESHDS_Mesh* mesh = 0, + list< const SMDS_MeshElement* >* elemQueue=0, + SMDSAbs_ElementType type=SMDSAbs_All) + { + for ( int iE = 0; iE < nbElems; ++iE ) + { + vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE]; + const int* select = & interlace[iE*nbNodes]; + elemNodes.resize( nbNodes ); + for ( int iN = 0; iN < nbNodes; ++iN ) + elemNodes[iN] = srcNodes[ select[ iN ]]; + } + const SMDS_MeshElement* e; + if ( elemQueue ) + for ( int iE = 0; iE < nbElems; ++iE ) + if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false))) + elemQueue->push_back( e ); + } +} + +//======================================================================= +/* + * Split bi-quadratic elements into linear ones without creation of additional nodes + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ +//======================================================================= + +void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems) +{ + vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8]; + vector splitElems; + list< const SMDS_MeshElement* > elemQueue; + list< const SMDS_MeshElement* >::iterator elemIt; + + SMESHDS_Mesh * mesh = GetMeshDS(); + ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge); + int nbElems, nbNodes; + + TIDSortedElemSet::iterator elemSetIt = theElems.begin(); + for ( ; elemSetIt != theElems.end(); ++elemSetIt ) + { + elemQueue.clear(); + elemQueue.push_back( *elemSetIt ); + for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt ) + { + const SMDS_MeshElement* elem = *elemIt; + switch( elem->GetEntityType() ) + { + case SMDSEntity_TriQuad_Hexa: // HEX27 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = nbNodes = 8; + elemType = & hexaType; + + // get nodes for new elements + static int vInd[8][8] = {{ 0,8,20,11, 16,21,26,24 }, + { 1,9,20,8, 17,22,26,21 }, + { 2,10,20,9, 18,23,26,22 }, + { 3,11,20,10, 19,24,26,23 }, + { 16,21,26,24, 4,12,25,15 }, + { 17,22,26,21, 5,13,25,12 }, + { 18,23,26,22, 6,14,25,13 }, + { 19,24,26,23, 7,15,25,14 }}; + selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes ); + + // add boundary faces to elemQueue + static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11, 20 }, + { 4,5,6,7, 12,13,14,15, 25 }, + { 0,1,5,4, 8,17,12,16, 21 }, + { 1,2,6,5, 9,18,13,17, 22 }, + { 2,3,7,6, 10,19,14,18, 23 }, + { 3,0,4,7, 11,16,15,19, 24 }}; + selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face ); + + // add boundary segments to elemQueue + static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 }, + { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 }, + { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Triangle: // TRIA7 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 3; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Quadrangle: // QUAD9 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 4; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_Quad_Edge: + { + if ( elemIt == elemQueue.begin() ) + continue; // an elem is in theElems + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 2; + nbNodes = 2; + elemType = & segType; + + // get nodes for new elements + static int eInd[2][2] = {{ 0,2 }, { 2,1 }}; + selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes ); + break; + } + default: continue; + } // switch( elem->GetEntityType() ) + + // Create new elements + + SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() ); + + splitElems.clear(); + + //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one + mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); + //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType )); + //elemType->SetID( -1 ); + + for ( int iE = 0; iE < nbElems; ++iE ) + splitElems.push_back( AddElement( splitNodes[ iE ], *elemType )); + + + ReplaceElemInGroups( elem, splitElems, mesh ); + + if ( subMesh ) + for ( size_t i = 0; i < splitElems.size(); ++i ) + subMesh->AddElement( splitElems[i] ); + } + } +} + +//======================================================================= +//function : AddToSameGroups +//purpose : add elemToAdd to the groups the elemInGroups belongs to +//======================================================================= + +void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, + const SMDS_MeshElement* elemInGroups, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->Contains( elemInGroups )) + group->SMDSGroup().Add( elemToAdd ); + } + } +} + + +//======================================================================= +//function : RemoveElemFromGroups +//purpose : Remove removeelem to the groups the elemInGroups belongs to +//======================================================================= +void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) + { + set::const_iterator GrIt = groups.begin(); + for (; GrIt != groups.end(); GrIt++) + { + SMESHDS_Group* grp = dynamic_cast(*GrIt); + if (!grp || grp->IsEmpty()) continue; + grp->SMDSGroup().Remove(removeelem); + } + } +} + +//================================================================================ +/*! + * \brief Replace elemToRm by elemToAdd in the all groups + */ +//================================================================================ + +void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, const SMDS_MeshElement* elemToAdd, SMESHDS_Mesh * aMesh) { @@ -2185,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 ] ); } } @@ -2200,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(); @@ -2237,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() ) { @@ -2270,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 ); @@ -2442,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; @@ -2551,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 ]; @@ -2629,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 ) @@ -2660,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 ) @@ -2683,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 ) @@ -2714,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 ) @@ -2742,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 @@ -3200,13 +3608,8 @@ static bool getClosestUV (Extrema_GenExtPS& projector, if ( projector.IsDone() ) { double u, v, minVal = DBL_MAX; for ( int i = projector.NbExt(); i > 0; i-- ) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 if ( projector.SquareDistance( i ) < minVal ) { minVal = projector.SquareDistance( i ); -#else - if ( projector.Value( i ) < minVal ) { - minVal = projector.Value( i ); -#endif projector.Point( i ).Parameter( u, v ); } result.SetCoord( u, v ); @@ -3232,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; @@ -3275,28 +3675,33 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // smooth elements on each TopoDS_Face separately // =============================================== - set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end - for ( ; fId != faceIdSet.rend(); ++fId ) { + SMESH_MesherHelper helper( *GetMesh() ); + + set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end + for ( ; fId != faceIdSet.rend(); ++fId ) + { // get face surface and submesh Handle(Geom_Surface) surface; SMESHDS_SubMesh* faceSubMesh = 0; 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 ) { + if ( *fId ) + { face = TopoDS::Face( aMesh->IndexToShape( *fId )); surface = BRep_Tool::Surface( face ); faceSubMesh = aMesh->MeshElements( *fId ); fToler2 = BRep_Tool::Tolerance( face ); fToler2 *= fToler2 * 10.; isUPeriodic = surface->IsUPeriodic(); - if ( isUPeriodic ) - 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 ); } // --------------------------------------------------------- // for elements on a face, find movable and fixed nodes and @@ -3318,7 +3723,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, int nbElemOnFace = 0; itElem = theElems.begin(); // loop on not yet smoothed elements: look for elems on a face - while ( itElem != theElems.end() ) { + while ( itElem != theElems.end() ) + { if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() ) break; // all elements found @@ -3352,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 ); @@ -3374,12 +3780,15 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // get nodes to check UV list< const SMDS_MeshNode* > uvCheckNodes; + const SMDS_MeshNode* nodeInFace = 0; itN = elem->nodesIterator(); nn = 0; nbn = elem->NbNodes(); if(elem->IsQuadratic()) nbn = nbn/2; while ( nn++ < nbn ) { node = static_cast( itN->next() ); + if ( node->GetPosition()->GetDim() == 2 ) + nodeInFace = node; if ( uvMap.find( node ) == uvMap.end() ) uvCheckNodes.push_back( node ); // add nodes of elems sharing node @@ -3405,41 +3814,21 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, const SMDS_PositionPtr& pos = node->GetPosition(); posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; // get existing UV - switch ( posType ) { - case SMDS_TOP_FACE: { - SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos; - uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() ); - break; - } - case SMDS_TOP_EDGE: { - TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() ); - Handle(Geom2d_Curve) pcurve; - if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE ) - pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l ); - if ( !pcurve.IsNull() ) { - double u = (( SMDS_EdgePosition* ) pos )->GetUParameter(); - uv = pcurve->Value( u ).XY(); - } - break; - } - case SMDS_TOP_VERTEX: { - TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() ); - if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX ) - uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY(); - break; - } - default:; - } - // check existing UV - bool project = true; - gp_Pnt pNode ( node->X(), node->Y(), node->Z() ); - double dist1 = DBL_MAX, dist2 = 0; - if ( posType != SMDS_TOP_3DSPACE ) { - dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() )); - project = dist1 > fToler2; - } + if ( pos ) + { + bool toCheck = true; + uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck ); + } + // compute not existing UV + bool project = ( posType == SMDS_TOP_3DSPACE ); + // double dist1 = DBL_MAX, dist2 = 0; + // if ( posType != SMDS_TOP_3DSPACE ) { + // dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() )); + // project = dist1 > fToler2; + // } if ( project ) { // compute new UV gp_XY newUV; + gp_Pnt pNode = SMESH_NodeXYZ( node ); if ( !getClosestUV( projector, pNode, newUV )) { MESSAGE("Node Projection Failed " << node); } @@ -3449,10 +3838,10 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, if ( isVPeriodic ) newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 )); // check new UV - if ( posType != SMDS_TOP_3DSPACE ) - dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); - if ( dist2 < dist1 ) - uv = newUV; + // if ( posType != SMDS_TOP_3DSPACE ) + // dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); + // if ( dist2 < dist1 ) + uv = newUV; } } // store UV in the map @@ -3519,9 +3908,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, uv2 = pcurve->Value( f ); int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2; // assure uv1 < uv2 - if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) { - gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp; - } + if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) + std::swap( uv1, uv2 ); // get nodes on seam and its vertices list< const SMDS_MeshNode* > seamNodes; SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes(); @@ -3571,12 +3959,14 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, setMovableNodes.find( n ) == setMovableNodes.end() ) continue; // add only nodes being closer to uv2 than to uv1 - gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ), - 0.5 * ( n->Y() + nSeam->Y() ), - 0.5 * ( n->Z() + nSeam->Z() )); - gp_XY uv; - getClosestUV( projector, pMid, uv ); - if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) { + // gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ), + // 0.5 * ( n->Y() + nSeam->Y() ), + // 0.5 * ( n->Z() + nSeam->Z() )); + // gp_XY uv; + // getClosestUV( projector, pMid, uv ); + double x = uvMap[ n ]->Coord( iPar ); + if ( Abs( uv1.Coord( iPar ) - x ) > + Abs( uv2.Coord( iPar ) - x )) { nodesNearSeam.insert( n ); nbUseMap2++; } @@ -3653,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, @@ -3685,8 +4075,6 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // move medium nodes of quadratic elements if ( isQuadratic ) { - SMESH_MesherHelper helper( *GetMesh() ); - helper.SetSubShape( face ); vector nodes; bool checkUV; list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); @@ -3695,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; @@ -3709,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() ); } @@ -3723,26 +4111,49 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, } -//======================================================================= -//function : isReverse -//purpose : Return true if normal of prevNodes is not co-directied with -// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). -// iNotSame is where prevNodes and nextNodes are different. -// If result is true then future volume orientation is OK -//======================================================================= - -static bool isReverse(const SMDS_MeshElement* face, - const vector& prevNodes, - const vector& nextNodes, - const int iNotSame) +namespace { + //======================================================================= + //function : isReverse + //purpose : Return true if normal of prevNodes is not co-directied with + // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). + // iNotSame is where prevNodes and nextNodes are different. + // If result is true then future volume orientation is OK + //======================================================================= + + bool isReverse(const SMDS_MeshElement* face, + const vector& prevNodes, + const vector& nextNodes, + const int iNotSame) + { + + SMESH_NodeXYZ pP = prevNodes[ iNotSame ]; + SMESH_NodeXYZ pN = nextNodes[ iNotSame ]; + gp_XYZ extrDir( pN - pP ), faceNorm; + SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); + + return faceNorm * extrDir < 0.0; + } - SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; - SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; - gp_XYZ extrDir( pN - pP ), faceNorm; - SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); + //================================================================================ + /*! + * \brief Assure that theElemSets[0] holds elements, not nodes + */ + //================================================================================ - return faceNorm * extrDir < 0.0; + void setElemsFirst( TIDSortedElemSet theElemSets[2] ) + { + if ( !theElemSets[0].empty() && + (*theElemSets[0].begin())->GetType() == SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + else if ( !theElemSets[1].empty() && + (*theElemSets[1].begin())->GetType() != SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + } } //======================================================================= @@ -3759,10 +4170,9 @@ static bool isReverse(const SMDS_MeshElement* face, 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(); @@ -3822,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 ); @@ -3842,6 +4252,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } } } + else if ( elem->GetType() == SMDSAbs_Edge ) + { + // orient a new face same as adjacent one + int i1, i2; + const SMDS_MeshElement* e; + TIDSortedElemSet dummy; + if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) || + ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) || + ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 ))) + { + // there is an adjacent face, check order of nodes in it + bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 ); + if ( sameOrder ) + { + std::swap( itNN[0], itNN[1] ); + std::swap( prevNod[0], prevNod[1] ); + std::swap( nextNod[0], nextNod[1] ); + std::swap( isSingleNode[0], isSingleNode[1] ); + if ( nbSame > 0 ) + sames[0] = 1 - sames[0]; + iNotSameNode = 1 - iNotSameNode; + } + } + } int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; if ( nbSame > 0 ) { @@ -3851,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++ ) @@ -3916,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], nextNod[1], prevNod[1], - nextNod[2], midlNod[1], prevNod[2]); - else // sames[0]==1 - aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1], - midlNod[0], nextNod[2], prevNod[2]); - } + 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; @@ -3996,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 @@ -4048,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 ) { @@ -4117,14 +4562,14 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, default: break; - } - } + } // switch ( baseType ) + } // scope if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism { if ( baseType != SMDSEntity_Polygon ) { - const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType); + const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes); SMDS_MeshCell::applyInterlace( ind, prevNod ); SMDS_MeshCell::applyInterlace( ind, nextNod ); SMDS_MeshCell::applyInterlace( ind, midlNod ); @@ -4149,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 ) @@ -4172,19 +4626,20 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, polyedre_nodes.resize( prevNbNodes ); } aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - } + + } // try to create a polyherdal prism if ( aNewElem ) { newElems.push_back( aNewElem ); - myLastCreatedElems.Append(aNewElem); - srcElements.Append( elem ); + myLastCreatedElems.push_back(aNewElem); + srcElements.push_back( elem ); } // set new prev nodes for ( iNode = 0; iNode < nbNodes; iNode++ ) prevNod[ iNode ] = nextNod[ iNode ]; - } // for steps + } // loop on steps } //======================================================================= @@ -4200,7 +4655,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, //======================================================================= void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, - TElemOfElemListMap & newElemsMap, + TTElemOfElemListMap & newElemsMap, TElemOfVecOfNnlmiMap & elemNewNodesMap, TIDSortedElemSet& elemSet, const int nbSteps, @@ -4223,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 ); @@ -4245,7 +4704,9 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // Make a ceiling for each element ie an equal element of last new nodes. // Find free links of faces - make edges and sweep them into faces. - TElemOfElemListMap::iterator itElem = newElemsMap.begin(); + ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace; + + TTElemOfElemListMap::iterator itElem = newElemsMap.begin(); TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) { @@ -4261,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 ); } } } @@ -4301,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 ); } } } @@ -4329,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 ); } } } @@ -4348,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; @@ -4371,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; @@ -4382,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])); @@ -4402,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; @@ -4428,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 @@ -4443,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 @@ -4462,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 @@ -4488,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 @@ -4513,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 @@ -4532,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 @@ -4559,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 ); - while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( elem ); + AddElement( nodeVec, anyFace.Init( elem )); + + while ( srcElements.size() < myLastCreatedElems.size() ) + srcElements.push_back( elem ); } } } // loop on swept elements @@ -4603,7 +5050,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, +SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], const gp_Ax1& theAxis, const double theAngle, const int theNbSteps, @@ -4611,13 +5058,17 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, 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; @@ -4630,89 +5081,93 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, TNodeOfNodeListMap mapNewNodes; TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; + TTElemOfElemListMap newElemsMap; const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC) + myMesh->NbVolumes(ORDER_QUADRATIC) ); - // loop on theElems + // loop on theElemSets TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* node = cast2Node( itN->next() ); - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + double coord[3]; + aXYZ.Coord( coord[0], coord[1], coord[2] ); + bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); - TNodeOfNodeListMapItr nIt = - mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - if ( listNewNodes.empty() ) - { - // check if we are to create medium nodes between corner ones - bool needMediumNodes = false; - if ( isQuadraticMesh ) + // check if a node has been already sweeped + TNodeOfNodeListMapItr nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while (it->more() && !needMediumNodes ) + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) { - const SMDS_MeshElement* invElem = it->next(); - if ( invElem != elem && !theElems.count( invElem )) continue; - needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); - if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) - needMediumNodes = true; + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } } - } - // make new nodes - const SMDS_MeshNode * newNode = node; - for ( int i = 0; i < theNbSteps; i++ ) { - if ( !isOnAxis ) { - if ( needMediumNodes ) // create a medium node - { - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + // make new nodes + const SMDS_MeshNode * newNode = node; + for ( int i = 0; i < theNbSteps; i++ ) { + if ( !isOnAxis ) { + if ( needMediumNodes ) // create a medium node + { + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( node ); + listNewNodes.push_back( newNode ); + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + } + else { + aTrsf.Transforms( coord[0], coord[1], coord[2] ); + } + // create a corner node newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); + myLastCreatedNodes.push_back(newNode); + srcNodes.push_back( node ); listNewNodes.push_back( newNode ); - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); } else { - aTrsf.Transforms( coord[0], coord[1], coord[2] ); + listNewNodes.push_back( newNode ); + // if ( needMediumNodes ) + // listNewNodes.push_back( newNode ); } - // create a corner node - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - else { - listNewNodes.push_back( newNode ); - // if ( needMediumNodes ) - // listNewNodes.push_back( newNode ); } } + newNodesItVec.push_back( nIt ); } - newNodesItVec.push_back( nIt ); + // make new elements + sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); } if ( theMakeWalls ) - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems ); PGroupIDs newGroupIDs; if ( theMakeGroups ) @@ -4721,252 +5176,604 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, return newGroupIDs; } - //======================================================================= -//function : CreateNode -//purpose : +//function : ExtrusParam +//purpose : standard construction //======================================================================= -const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x, - const double y, - const double z, - const double tolnode, - SMESH_SequenceOfNode& aNodes) -{ - // myLastCreatedElems.Clear(); - // myLastCreatedNodes.Clear(); - gp_Pnt P1(x,y,z); - SMESHDS_Mesh * aMesh = myMesh->GetMeshDS(); +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 ) +{ + mySteps = new TColStd_HSequenceOfReal; + const double stepSize = theStep.Magnitude(); + for (int i=1; i<=theNbSteps; i++ ) + mySteps->Append( stepSize ); - // try to search in sequence of existing nodes - // if aNodes.Length()>0 we 'nave to use given sequence - // else - use all nodes of mesh - if(aNodes.Length()>0) { - int i; - for(i=1; i<=aNodes.Length(); i++) { - gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z()); - if(P1.Distance(P2) 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 { - SMDS_NodeIteratorPtr itn = aMesh->nodesIterator(); - while(itn->more()) { - const SMDS_MeshNode* aN = static_cast (itn->next()); - gp_Pnt P2(aN->X(),aN->Y(),aN->Z()); - if(P1.Distance(P2)AddNode(x,y,z); - //myLastCreatedNodes.Append(NewNode); - return NewNode; + if (( theFlags & EXTRUSION_FLAG_SEW ) && + ( theTolerance > 0 )) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir; + } } - //======================================================================= -//function : ExtrusionSweep -//purpose : +//function : ExtrusParam +//purpose : steps are given explicitly //======================================================================= -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, - const gp_Vec& theStep, - const int theNbSteps, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance) +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir& theDir, + Handle(TColStd_HSequenceOfReal) theSteps, + const int theFlags, + const double theTolerance): + myDir( theDir ), + mySteps( theSteps ), + myFlags( theFlags ), + myTolerance( theTolerance ), + myElemsToUse( NULL ) { - ExtrusParam aParams; - aParams.myDir = gp_Dir(theStep); - aParams.myNodes.Clear(); - aParams.mySteps = new TColStd_HSequenceOfReal; - int i; - for(i=1; i<=theNbSteps; i++) - aParams.mySteps->Append(theStep.Magnitude()); - - return - ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance); + if (( theFlags & EXTRUSION_FLAG_SEW ) && + ( theTolerance > 0 )) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir; + } } - //======================================================================= -//function : ExtrusionSweep -//purpose : +//function : ExtrusParam +//purpose : for extrusion by normal //======================================================================= -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, - ExtrusParam& theParams, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance) +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize, + const int theNbSteps, + const int theFlags, + const int theDim ): + myDir( 1,0,0 ), + mySteps( new TColStd_HSequenceOfReal ), + myFlags( theFlags ), + myTolerance( 0 ), + myElemsToUse( NULL ) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; + for (int i = 0; i < theNbSteps; i++ ) + mySteps->Append( theStepSize ); - SMESHDS_Mesh* aMesh = GetMeshDS(); - - int nbsteps = theParams.mySteps->Length(); + if ( theDim == 1 ) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D; + } +} - TNodeOfNodeListMap mapNewNodes; - //TNodeOfNodeVecMap mapNewNodes; - TElemOfVecOfNnlmiMap mapElemNewNodes; - //TElemOfVecOfMapNodesMap mapElemNewNodes; +//======================================================================= +//function : ExtrusParam::SetElementsToUse +//purpose : stores elements to use for extrusion by normal, depending on +// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag; +// define myBaseP for scaling +//======================================================================= - const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + - myMesh->NbFaces(ORDER_QUADRATIC) + - myMesh->NbVolumes(ORDER_QUADRATIC) ); - // loop on theElems - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; +void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems, + const TIDSortedElemSet& nodes ) +{ + myElemsToUse = ToUseInpElemsOnly() ? & elems : 0; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + if ( Precision::IsInfinite( myBaseP.X() )) // myBaseP not defined + { + myBaseP.SetCoord( 0.,0.,0. ); + TIDSortedElemSet newNodes; - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) + const TIDSortedElemSet* elemSets[] = { &elems, &nodes }; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); - TNodeOfNodeListMap::iterator nIt = - mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - if ( listNewNodes.empty() ) + const TIDSortedElemSet& elements = *( elemSets[ is2ndSet ]); + TIDSortedElemSet::const_iterator itElem = elements.begin(); + for ( ; itElem != elements.end(); itElem++ ) { - // make new nodes - - // check if we are to create medium nodes between corner ones - bool needMediumNodes = false; - if ( isQuadraticMesh ) - { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while (it->more() && !needMediumNodes ) - { - const SMDS_MeshElement* invElem = it->next(); - if ( invElem != elem && !theElems.count( invElem )) continue; - needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); - if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) - needMediumNodes = true; - } - } - - double coord[] = { node->X(), node->Y(), node->Z() }; - for ( int i = 0; i < nbsteps; i++ ) - { - if ( needMediumNodes ) // create a medium node - { - double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.; - double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.; - double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.; - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(x, y, z, - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - } - // create a corner node - coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2], - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } + 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 ); } } - newNodesItVec.push_back( nIt ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems ); + myBaseP /= newNodes.size(); } +} - if( theFlags & EXTRUSION_FLAG_BOUNDARY ) { - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems ); - } - PGroupIDs newGroupIDs; - if ( theMakeGroups ) - newGroupIDs = generateGroups( srcNodes, srcElems, "extruded"); +//======================================================================= +//function : ExtrusParam::beginStepIter +//purpose : prepare iteration on steps +//======================================================================= - return newGroupIDs; +void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes ) +{ + myWithMediumNodes = withMediumNodes; + myNextStep = 1; + myCurSteps.clear(); } +//======================================================================= +//function : ExtrusParam::moreSteps +//purpose : are there more steps? +//======================================================================= +bool SMESH_MeshEditor::ExtrusParam::moreSteps() +{ + return myNextStep <= mySteps->Length() || !myCurSteps.empty(); +} //======================================================================= -//function : ExtrusionAlongTrack -//purpose : +//function : ExtrusParam::nextStep +//purpose : returns the next step //======================================================================= -SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, - SMESH_subMesh* theTrack, - const SMDS_MeshNode* theN1, - const bool theHasAngles, - list& theAngles, - const bool theLinearVariation, - const bool theHasRefPoint, - const gp_Pnt& theRefPoint, - const bool theMakeGroups) + +double SMESH_MeshEditor::ExtrusParam::nextStep() { - MESSAGE("ExtrusionAlongTrack"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + double res = 0; + if ( !myCurSteps.empty() ) + { + res = myCurSteps.back(); + myCurSteps.pop_back(); + } + else if ( myNextStep <= mySteps->Length() ) + { + myCurSteps.push_back( mySteps->Value( myNextStep )); + ++myNextStep; + if ( myWithMediumNodes ) + { + myCurSteps.back() /= 2.; + myCurSteps.push_back( myCurSteps.back() ); + } + res = nextStep(); + } + return res; +} - int aNbE; - std::list aPrms; - TIDSortedElemSet::iterator itElem; +//======================================================================= +//function : ExtrusParam::makeNodesByDir +//purpose : create nodes for standard extrusion +//======================================================================= - gp_XYZ aGC; - TopoDS_Edge aTrackEdge; - TopoDS_Vertex aV1, aV2; +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByDir( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + gp_XYZ p = SMESH_NodeXYZ( srcNode ); - SMDS_ElemIteratorPtr aItE; - SMDS_NodeIteratorPtr aItN; - SMDSAbs_ElementType aTypeE; + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + p += myDir.XYZ() * nextStep(); + const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); + newNodes.push_back( newNode ); + } - TNodeOfNodeListMap mapNewNodes; + 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() }; - // 1. Check data - aNbE = theElements.size(); - // nothing to do - if ( !aNbE ) - return EXTR_NO_ELEMENTS; + size_t iSc = 0, nbScales = myScales.size() + myMediumScales.size(); - // 1.1 Track Pattern - ASSERT( theTrack ); + 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(); - SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS(); + 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() ); - aItE = pSubMeshDS->GetElements(); - while ( aItE->more() ) { - const SMDS_MeshElement* pE = aItE->next(); - aTypeE = pE->GetType(); - // Pattern must contain links only - if ( aTypeE != SMDSAbs_Edge ) - return EXTR_PATH_NOT_EDGE; + ++scale; + } + } + return nbNodes; +} + +//======================================================================= +//function : ExtrusParam::makeNodesByDirAndSew +//purpose : create nodes for standard extrusion with sewing +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByDirAndSew( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + gp_XYZ P1 = SMESH_NodeXYZ( srcNode ); + + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + P1 += myDir.XYZ() * nextStep(); + + // try to search in sequence of existing nodes + // if myNodes.size()>0 we 'nave to use given sequence + // else - use all nodes of mesh + const SMDS_MeshNode * node = 0; + 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); + break; + } + } + } + else + { + SMDS_NodeIteratorPtr itn = mesh->nodesIterator(); + while(itn->more()) + { + SMESH_NodeXYZ P2 = itn->next(); + if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) + { + node = P2._node; + break; + } + } + } + + if ( !node ) + node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() ); + + newNodes.push_back( node ); + + } // loop on steps + + return nbNodes; +} + +//======================================================================= +//function : ExtrusParam::makeNodesByNormal2D +//purpose : create nodes for extrusion using normals of faces +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByNormal2D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ); + + gp_XYZ p = SMESH_NodeXYZ( srcNode ); + + // get normals to faces sharing srcNode + vector< gp_XYZ > norms, baryCenters; + gp_XYZ norm, avgNorm( 0,0,0 ); + SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( myElemsToUse && !myElemsToUse->count( face )) + continue; + if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true )) + { + norms.push_back( norm ); + avgNorm += norm; + if ( !alongAvgNorm ) + { + gp_XYZ bc(0,0,0); + int nbN = 0; + for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN ) + bc += SMESH_NodeXYZ( nIt->next() ); + baryCenters.push_back( bc / nbN ); + } + } + } + + if ( norms.empty() ) return 0; + + double normSize = avgNorm.Modulus(); + if ( normSize < std::numeric_limits::min() ) + return 0; + + if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm + { + myDir = avgNorm; + return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes ); + } + + avgNorm /= normSize; + + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + gp_XYZ pNew = p; + double stepSize = nextStep(); + + if ( norms.size() > 1 ) + { + for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces + { + // translate plane of a face + baryCenters[ iF ] += norms[ iF ] * stepSize; + + // find point of intersection of the face plane located at baryCenters[ iF ] + // and avgNorm located at pNew + double d = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0 + double dot = ( norms[ iF ] * avgNorm ); + if ( dot < std::numeric_limits::min() ) + dot = stepSize * 1e-3; + double step = -( norms[ iF ] * pNew + d ) / dot; + pNew += step * avgNorm; + } + } + else + { + pNew += stepSize * avgNorm; + } + p = pNew; + + const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); + newNodes.push_back( newNode ); + } + return nbNodes; +} + +//======================================================================= +//function : ExtrusParam::makeNodesByNormal1D +//purpose : create nodes for extrusion using normals of edges +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByNormal1D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + throw SALOME_Exception("Extrusion 1D by Normal not implemented"); + return 0; +} + +//======================================================================= +//function : ExtrusionSweep +//purpose : +//======================================================================= + +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElems[2], + const gp_Vec& theStep, + const int theNbSteps, + TTElemOfElemListMap& newElemsMap, + const int theFlags, + const double theTolerance) +{ + ExtrusParam aParams( theStep, theNbSteps, std::list(), 0, theFlags, theTolerance ); + return ExtrusionSweep( theElems, aParams, newElemsMap ); +} + + +//======================================================================= +//function : ExtrusionSweep +//purpose : +//======================================================================= + +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2], + ExtrusParam& theParams, + TTElemOfElemListMap& newElemsMap) +{ + 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() ); + + const int nbSteps = theParams.NbSteps(); + theParams.SetElementsToUse( theElemSets[0], theElemSets[1] ); + + TNodeOfNodeListMap mapNewNodes; + TElemOfVecOfNnlmiMap mapElemNewNodes; + + const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + + myMesh->NbFaces(ORDER_QUADRATIC) + + myMesh->NbVolumes(ORDER_QUADRATIC) ); + // loop on theElems + TIDSortedElemSet::iterator itElem; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + // check element type + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; + + const size_t nbNodes = elem->NbNodes(); + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( nbNodes ); + + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + // check if a node has been already sweeped + const SMDS_MeshNode* node = cast2Node( itN->next() ); + TNodeOfNodeListMap::iterator nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) + { + // make new nodes + + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) + { + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } + } + // create nodes for all steps + if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes )) + { + list::iterator newNodesIt = listNewNodes.begin(); + for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt ) + { + myLastCreatedNodes.push_back( *newNodesIt ); + srcNodes.push_back( node ); + } + } + else + { + break; // newNodesItVec will be shorter than nbNodes + } + } + newNodesItVec.push_back( nIt ); + } + // make new elements + if ( newNodesItVec.size() == nbNodes ) + sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems ); + } + } + + if ( theParams.ToMakeBoundary() ) { + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems ); + } + PGroupIDs newGroupIDs; + if ( theParams.ToMakeGroups() ) + newGroupIDs = generateGroups( srcNodes, srcElems, "extruded"); + + return newGroupIDs; +} + +//======================================================================= +//function : ExtrusionAlongTrack +//purpose : +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], + SMESH_subMesh* theTrack, + const SMDS_MeshNode* theN1, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) +{ + ClearLastCreated(); + + int aNbE; + std::list aPrms; + TIDSortedElemSet::iterator itElem; + + gp_XYZ aGC; + TopoDS_Edge aTrackEdge; + TopoDS_Vertex aV1, aV2; + + SMDS_ElemIteratorPtr aItE; + SMDS_NodeIteratorPtr aItN; + SMDSAbs_ElementType aTypeE; + + TNodeOfNodeListMap mapNewNodes; + + // 1. Check data + aNbE = theElements[0].size() + theElements[1].size(); + // nothing to do + if ( !aNbE ) + return EXTR_NO_ELEMENTS; + + // 1.1 Track Pattern + 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() ) { + const SMDS_MeshElement* pE = aItE->next(); + aTypeE = pE->GetType(); + // Pattern must contain links only + if ( aTypeE != SMDSAbs_Edge ) + return EXTR_PATH_NOT_EDGE; } list fullList; @@ -4976,7 +5783,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, if( aS.ShapeType() == TopAbs_EDGE ) { aTrackEdge = TopoDS::Edge( aS ); // the Edge must not be degenerated - if ( BRep_Tool::Degenerated( aTrackEdge ) ) + if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) return EXTR_BAD_PATH_SHAPE; TopExp::Vertices( aTrackEdge, aV1, aV2 ); aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); @@ -4988,14 +5795,13 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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; @@ -5033,17 +5839,16 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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; @@ -5083,7 +5888,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, return EXTR_BAD_PATH_SHAPE; } - return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, theHasRefPoint, theRefPoint, theMakeGroups); } @@ -5093,7 +5898,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, //purpose : //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_Mesh* theTrack, const SMDS_MeshNode* theN1, const bool theHasAngles, @@ -5103,8 +5908,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, const gp_Pnt& theRefPoint, const bool theMakeGroups) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); int aNbE; std::list aPrms; @@ -5121,7 +5925,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TNodeOfNodeListMap mapNewNodes; // 1. Check data - aNbE = theElements.size(); + aNbE = theElements[0].size() + theElements[1].size(); // nothing to do if ( !aNbE ) return EXTR_NO_ELEMENTS; @@ -5144,7 +5948,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, const TopoDS_Shape& aS = theTrack->GetShapeToMesh(); - if( aS == SMESH_Mesh::PseudoShape() ) { + if ( !theTrack->HasShapeToMesh() ) { //Mesh without shape const SMDS_MeshNode* currentNode = NULL; const SMDS_MeshNode* prevNode = theN1; @@ -5157,12 +5961,12 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, SMDS_ElemIteratorPtr nIt; //check start node - if( !theTrack->GetMeshDS()->Contains(theN1) ) { + if( !theTrack->GetMeshDS()->Contains( theN1 )) { return EXTR_BAD_STARTING_NODE; } conn = nbEdgeConnectivity(theN1); - if(conn > 2) + if( conn != 1 ) return EXTR_PATH_NOT_EDGE; aItE = theN1->GetInverseElementIterator(); @@ -5213,21 +6017,19 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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(); @@ -5247,8 +6049,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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++; @@ -5261,22 +6062,15 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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 ( BRep_Tool::Degenerated( aTrackEdge ) ) + if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) return EXTR_BAD_PATH_SHAPE; TopExp::Vertices( aTrackEdge, aV1, aV2 ); - const SMDS_MeshNode* aN1 = 0; - const SMDS_MeshNode* aN2 = 0; - if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) { - aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); - aN1 = aItN->next(); - } - if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) { - aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); - aN2 = aItN->next(); - } + const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS ); + const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS ); // starting node must be aN1 or aN2 if ( !( aN1 == theN1 || aN2 == theN1 ) ) return EXTR_BAD_STARTING_NODE; @@ -5284,13 +6078,12 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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; @@ -5298,7 +6091,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TopExp_Explorer eExp(aS, TopAbs_EDGE); for(; eExp.More(); eExp.Next()) { TopoDS_Edge E = TopoDS::Edge( eExp.Current() ); - if( BRep_Tool::Degenerated(E) ) continue; + if( SMESH_Algo::isDegenerated(E) ) continue; SMESH_subMesh* SM = theTrack->GetSubMesh(E); if(SM) { LSM.push_back(SM); @@ -5324,17 +6117,8 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, if ( aVprev.IsNull() ) { // if previous vertex is not yet defined, it means that we in the beginning of wire // and we have to find initial vertex corresponding to starting node theN1 - const SMDS_MeshNode* aN1 = 0; - const SMDS_MeshNode* aN2 = 0; - - if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) { - aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes(); - aN1 = aItN->next(); - } - if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) { - aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes(); - aN2 = aItN->next(); - } + const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS ); + const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS ); // starting node must be aN1 or aN2 aN1isOK = ( aN1 && aN1 == theN1 ); aN2isOK = ( aN2 && aN2 == theN1 ); @@ -5350,45 +6134,38 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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; } } list< list >::iterator itLLPP = LLPPs.begin(); - list firstList = *itLLPP; - list::iterator itPP = firstList.begin(); - for(; itPP!=firstList.end(); itPP++) { - fullList.push_back( *itPP ); - } + list& firstList = *itLLPP; + fullList.splice( fullList.end(), firstList ); + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); fullList.pop_back(); itLLPP++; for(; itLLPP!=LLPPs.end(); itLLPP++) { - list currList = *itLLPP; - itPP = currList.begin(); + list& currList = *itLLPP; SMESH_MeshEditor_PathPoint PP2 = currList.front(); gp_Dir D1 = PP1.Tangent(); gp_Dir D2 = PP2.Tangent(); - gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 ); + gp_Dir Dnew( D1.XYZ() + D2.XYZ() ); PP1.SetTangent(Dnew); fullList.push_back(PP1); - itPP++; - for(; itPP!=currList.end(); itPP++) { - fullList.push_back( *itPP ); - } + fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() ); PP1 = fullList.back(); fullList.pop_back(); } @@ -5400,19 +6177,19 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, 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, - const TopoDS_Edge& aTrackEdge, - bool FirstIsStart, +SMESH_MeshEditor::makeEdgePathPoints(std::list& aPrms, + const TopoDS_Edge& aTrackEdge, + bool FirstIsStart, list& LPP) { Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; @@ -5450,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 ); @@ -5461,207 +6238,175 @@ 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& theElements, +SMESH_MeshEditor::makeExtrElements(TIDSortedElemSet theElemSets[2], list& fullList, - const bool theHasAngles, - list& theAngles, - const bool theLinearVariation, - const bool theHasRefPoint, - const gp_Pnt& theRefPoint, - const bool theMakeGroups) + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) { - MESSAGE("MakeExtrElements"); - //cout<<"MakeExtrElements fullList.size() = "< aPPs(aNbTP); + const int aNbTP = fullList.size(); + // Angles - if( theHasAngles && theAngles.size()>0 && theLinearVariation ) { - LinearAngleVariation(aNbTP-1, theAngles); - } - vector aAngles( aNbTP ); - int j = 0; - for(; j::iterator aItD = theAngles.begin(); - for ( j=1; (aItD != theAngles.end()) && (j aPPs; list::iterator itPP = fullList.begin(); - for(; itPP!=fullList.end(); itPP++) { - j++; - SMESH_MeshEditor_PathPoint PP = *itPP; - PP.SetAngle(aAngles[j]); - aPPs[j] = PP; + list::iterator itAngles = theAngles.begin(); + aPPs.push_back( *itPP++ ); + for( ; itPP != fullList.end(); itPP++) { + aPPs.push_back( *itPP ); + if ( theHasAngles && itAngles != theAngles.end() ) + aPPs.back().SetAngle( *itAngles++ ); } - TNodeOfNodeListMap mapNewNodes; + TNodeOfNodeListMap mapNewNodes; TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; + TTElemOfElemListMap newElemsMap; TIDSortedElemSet::iterator itElem; - double aX, aY, aZ; - int aNb; - SMDSAbs_ElementType aTypeE; // source elements for each generated one SMESH_SequenceOfElemPtr srcElems, srcNodes; // 3. Center of rotation aV0 gp_Pnt aV0 = theRefPoint; - gp_XYZ aGC; - if ( !theHasRefPoint ) { - aNb = 0; - aGC.SetCoord( 0.,0.,0. ); - - itElem = theElements.begin(); - for ( ; itElem != theElements.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = static_cast( itN->next() ); - aX = node->X(); - aY = node->Y(); - aZ = node->Z(); + if ( !theHasRefPoint ) + { + gp_XYZ aGC( 0.,0.,0. ); + TIDSortedElemSet newNodes; - if ( mapNewNodes.find( node ) == mapNewNodes.end() ) { - list aLNx; - mapNewNodes[node] = aLNx; - // - gp_XYZ aXYZ( aX, aY, aZ ); - aGC += aXYZ; - ++aNb; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + itElem = theElements.begin(); + for ( ; itElem != theElements.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 ) + aGC += SMESH_NodeXYZ( node ); } } } - aGC /= aNb; + aGC /= newNodes.size(); aV0.SetXYZ( aGC ); } // if (!theHasRefPoint) { - mapNewNodes.clear(); // 4. Processing the elements SMESHDS_Mesh* aMesh = GetMeshDS(); + list emptyList; - for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - aTypeE = elem->GetType(); - if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) ) - continue; + setElemsFirst( theElemSets ); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - // loop on elem nodes - int nodeIndex = -1; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - ++nodeIndex; - // check if a node has been already processed - const SMDS_MeshNode* node = - static_cast( itN->next() ); - TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) { - nIt = mapNewNodes.insert( make_pair( node, list() )).first; + // loop on elem nodes + int nodeIndex = -1; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + ++nodeIndex; + // check if a node has been already processed + const SMDS_MeshNode* node = 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; + gp_Ax1 anAx1, anAxT1T0; + gp_Dir aDT1x, aDT0x, aDT1T0; + + aTolAng=1.e-4; + + aV0x = aV0; + aPN0 = SMESH_NodeXYZ( node ); + + const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; + aP0x = aPP0.Pnt(); + aDT0x= aPP0.Tangent(); + + for ( int j = 1; j < aNbTP; ++j ) { + const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j]; + aP1x = aPP1.Pnt(); + aDT1x = aPP1.Tangent(); + aAngle1x = aPP1.Angle(); + + gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0; + // Translation + gp_Vec aV01x( aP0x, aP1x ); + aTrsf.SetTranslation( aV01x ); + + // traslated point + aV1x = aV0x.Transformed( aTrsf ); + aPN1 = aPN0.Transformed( aTrsf ); + + // rotation 1 [ T1,T0 ] + aAngleT1T0=-aDT1x.Angle( aDT0x ); + if (fabs(aAngleT1T0) > aTolAng) + { + aDT1T0=aDT1x^aDT0x; + anAxT1T0.SetLocation( aV1x ); + anAxT1T0.SetDirection( aDT1T0 ); + aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); - // make new nodes - aX = node->X(); aY = node->Y(); aZ = node->Z(); - - Standard_Real aAngle1x, aAngleT1T0, aTolAng; - gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; - gp_Ax1 anAx1, anAxT1T0; - gp_Dir aDT1x, aDT0x, aDT1T0; - - aTolAng=1.e-4; - - aV0x = aV0; - aPN0.SetCoord(aX, aY, aZ); - - const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; - aP0x = aPP0.Pnt(); - aDT0x= aPP0.Tangent(); - //cout<<"j = 0 PP: Pnt("< aTolAng) { - aDT1T0=aDT1x^aDT0x; - anAxT1T0.SetLocation( aV1x ); - anAxT1T0.SetDirection( aDT1T0 ); - aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); - - aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); - } + aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); + } - // rotation 2 - if ( theHasAngles ) { - anAx1.SetLocation( aV1x ); - anAx1.SetDirection( aDT1x ); - aTrsfRot.SetRotation( anAx1, aAngle1x ); + // rotation 2 + if ( theHasAngles ) { + anAx1.SetLocation( aV1x ); + anAx1.SetDirection( aDT1x ); + aTrsfRot.SetRotation( anAx1, aAngle1x ); - aPN1 = aPN1.Transformed( aTrsfRot ); - } + aPN1 = aPN1.Transformed( aTrsfRot ); + } - // make new node - //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node)); - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create additional node - double x = ( aPN1.X() + aPN0.X() )/2.; - double y = ( aPN1.Y() + aPN0.Y() )/2.; - double z = ( aPN1.Z() + aPN0.Z() )/2.; - const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); + // make new node + if ( elem->IsQuadratic() && !elem->IsMediumNode(node) ) + { + // create additional 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.push_back(newNode); + srcNodes.push_back( node ); listNewNodes.push_back( newNode ); - } - aX = aPN1.X(); - aY = aPN1.Y(); - aZ = aPN1.Z(); - const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - aPN0 = aPN1; - aP0x = aP1x; - aV0x = aV1x; - aDT0x = aDT1x; + aPN0 = aPN1; + aP0x = aP1x; + aV0x = aV1x; + aDT0x = aDT1x; + } } - } - - else { - // if current elem is quadratic and current node is not medium - // we have to check - may be it is needed to insert additional nodes - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + 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 list< const SMDS_MeshNode* > & listNewNodes = nIt->second; - if(listNewNodes.size()==aNbTP-1) { + 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(); @@ -5672,8 +6417,8 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements, 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); + 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()); @@ -5684,17 +6429,16 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements, } } } + + newNodesItVec.push_back( nIt ); } - newNodesItVec.push_back( nIt ); + // make new elements + sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } - // make new elements - //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], - // newNodesItVec[0]->second.size(), myLastCreatedElems ); - sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems ); if ( theMakeGroups ) generateGroups( srcNodes, srcElems, "extruded"); @@ -5704,25 +6448,24 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements, //======================================================================= -//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 ); @@ -5744,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 ); } } @@ -5771,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; @@ -5848,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 @@ -6045,32 +6699,112 @@ 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 ) || ( theMakeGroups && theTargetMesh ) ) - newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh ); + newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false ); + + return newGroupIDs; +} + +//================================================================================ +/*! + * \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::Offset( TIDSortedElemSet & theElements, + const double theValue, + SMESH_Mesh* theTgtMesh, + const bool theMakeGroups, + const bool theFixSelfIntersection) +{ + SMESHDS_Mesh* meshDS = GetMeshDS(); + SMESHDS_Mesh* tgtMeshDS = theTgtMesh->GetMeshDS(); + SMESH_MeshEditor tgtEditor( theTgtMesh ); + + SMDS_ElemIteratorPtr eIt; + if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face ); + else eIt = SMESHUtils::elemSetIterator( theElements ); + + SMESH_MeshAlgos::TEPairVec new2OldFaces; + SMESH_MeshAlgos::TNPairVec new2OldNodes; + std::unique_ptr< SMDS_Mesh > offsetMesh + ( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue, + theFixSelfIntersection, + new2OldFaces, new2OldNodes )); + + 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; } @@ -6078,9 +6812,11 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, //======================================================================= /*! * \brief Create groups of elements made during transformation - * \param nodeGens - nodes making corresponding myLastCreatedNodes - * \param elemGens - elements making corresponding myLastCreatedElems - * \param postfix - to append to names of new groups + * \param nodeGens - nodes making corresponding myLastCreatedNodes + * \param elemGens - elements making corresponding myLastCreatedElems + * \param postfix - to 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 */ //======================================================================= @@ -6088,14 +6824,17 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, const SMESH_SequenceOfElemPtr& elemGens, const std::string& postfix, - SMESH_Mesh* targetMesh) + SMESH_Mesh* targetMesh, + const bool topPresent) { PGroupIDs newGroupIDs( new list ); SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh(); // Sort existing groups by types and collect their names - // to store an old group and a generated new ones + // 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; @@ -6125,56 +6864,55 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, // Loop on nodes and elements to add them in new groups + vector< const SMDS_MeshElement* > resultElems; for ( int isNodes = 0; isNodes < 2; ++isNodes ) { const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems; - if ( gens.Length() != elems.Length() ) + 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 - list< const SMDS_MeshElement* > resultElems; - if ( const SMDS_MeshElement* resElem = elems( iElem )) + resultElems.clear(); + 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 ); - // there must be a top element const SMDS_MeshElement* topElem = 0; - if ( isNodes ) + if ( isNodes ) // there must be a top element { topElem = resultElems.back(); resultElems.pop_back(); } else { - list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin(); + vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin(); for ( ; resElemIt != resultElems.rend() ; ++resElemIt ) if ( (*resElemIt)->GetType() == sourceElem->GetType() ) { topElem = *resElemIt; - resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt + *resElemIt = 0; // erase *resElemIt break; } } - // add resultElems to groups originted from ones the sourceElem belongs to list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end(); for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew ) @@ -6184,9 +6922,10 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, { // fill in a new group SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup(); - list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; + vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt ) - newGroup.Add( *resElemIt ); + if ( *resElemIt ) + newGroup.Add( *resElemIt ); // fill a "top" group if ( topElem ) @@ -6207,7 +6946,6 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>(); SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(), orderedOldNewGroups[i]->get<2>() }; - const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty(); for ( int is2nd = 0; is2nd < 2; ++is2nd ) { SMESHDS_Group* newGroupDS = newGroups[ is2nd ]; @@ -6221,11 +6959,21 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() ); // make a name - const bool isTop = ( nbNewGroups == 2 && + const bool isTop = ( topPresent && newGroupDS->GetType() == oldGroupDS->GetType() && is2nd ); string name = oldGroupDS->GetStoreName(); + { // remove trailing whitespaces (issue 22599) + size_t size = name.size(); + while ( size > 1 && isspace( name[ size-1 ])) + --size; + if ( size != name.size() ) + { + name.resize( size ); + oldGroupDS->SetStoreName( name.c_str() ); + } + } if ( !targetMesh ) { string suffix = ( isTop ? "top": postfix.c_str() ); name += "_"; @@ -6255,32 +7003,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, @@ -6288,78 +7075,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; } //======================================================================= @@ -6368,41 +7129,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(); @@ -6410,640 +7160,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; - } - else - isOk = false; - } - else - isOk = false; - break; - case 8: { - if(elem->IsQuadratic()) { // Quadratic quadrangle - // 1 5 2 - // +---+---+ - // | | - // | | - // 4+ +6 - // | | - // | | - // +---+---+ - // 0 7 3 - isOk = false; - if(nbRepl==2) { - MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]); - } - if(nbRepl==3) { - MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]); - nbUniqueNodes = 6; - if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[5]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[6]; - isOk = true; - } - if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[1]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[5]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[0]; - isOk = true; - } - if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[1]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[2]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[3]; - isOk = true; - } - } - if(nbRepl==4) { - MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]); - } - if(nbRepl==5) { - MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]); + 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); } - 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; + } + } + + 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); } - } - 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] )) + + if ( quantities.size() > 3 ) { - 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; - } + // TODO: remove coincident faces + nbResElems = 1; + nbUniqueNodes = newElemDefs[0].myNodes.size(); } - 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; }; //======================================================================= @@ -7052,52 +7786,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 ); } } } @@ -7109,8 +7838,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 @@ -7149,8 +7877,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 ); } //======================================================================= @@ -7168,6 +7896,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 : @@ -7192,7 +7938,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 ); @@ -7204,32 +7949,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 ) || @@ -7296,7 +8027,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 @@ -7331,6 +8062,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 @@ -7344,19 +8077,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 @@ -7392,7 +8123,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 ]; @@ -7455,7 +8186,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(); @@ -7480,33 +8211,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; @@ -7556,7 +8273,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 ); @@ -7592,12 +8309,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 @@ -7615,10 +8346,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 ]; @@ -7663,8 +8393,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 @@ -7688,10 +8418,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()); @@ -7701,7 +8431,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: @@ -7711,12 +8441,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 @@ -7728,8 +8457,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 ); } @@ -7763,14 +8491,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) { @@ -7778,69 +8506,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 ; @@ -7869,73 +8684,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 ]; @@ -7948,7 +8719,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; @@ -7984,41 +8755,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; @@ -8045,66 +8807,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; @@ -8112,36 +8846,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 @@ -8197,24 +8934,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 ); } } @@ -8244,7 +8973,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 */ //======================================================================= @@ -8253,6 +8982,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, SMESH_MesherHelper& theHelper, const bool theForce3d) { + //MESSAGE("convertElemToQuadratic"); int nbElem = 0; if( !theSm ) return nbElem; @@ -8278,18 +9008,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; @@ -8308,14 +9040,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 ) @@ -8326,50 +9058,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; } @@ -8386,6 +9120,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); @@ -8393,6 +9128,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT aHelper.SetIsQuadratic( true ); aHelper.SetIsBiQuadratic( theToBiQuad ); aHelper.SetElementsOnShape(true); + aHelper.ToFixNodeParameters( true ); // convert elements assigned to sub-meshes int nbCheckedElems = 0; @@ -8505,16 +9241,27 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theT if ( !volume ) continue; const SMDSAbs_EntityType type = volume->GetEntityType(); - if (( theToBiQuad && type == SMDSEntity_TriQuad_Hexa ) || - ( !theToBiQuad && type == SMDSEntity_Quad_Hexa )) + if ( volume->IsQuadratic() ) { - aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume )); - continue; + bool alreadyOK; + switch ( type ) + { + 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 ) + { + aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume )); + continue; + } } const int id = volume->GetID(); vector nodes (volume->begin_nodes(), volume->end_nodes()); if ( type == SMDSEntity_Polyhedra ) - nbNodeInFaces = static_cast(volume)->GetQuantities(); + nbNodeInFaces = static_cast(volume)->GetQuantities(); else if ( type == SMDSEntity_Hexagonal_Prism ) volumeToPolyhedron( volume, nodes, nbNodeInFaces ); @@ -8540,8 +9287,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: @@ -8729,7 +9481,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 ); @@ -8757,6 +9509,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int nbElem = 0; SMESHDS_Mesh* meshDS = GetMeshDS(); + ElemFeatures elemType; + vector nodes; while( theItr->more() ) { @@ -8764,11 +9518,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 )) @@ -8776,13 +9530,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 ); @@ -8861,7 +9615,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 @@ -8913,7 +9667,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) } } } - elemIt = elemSetIterator( moreElemsToConvert ); + elemIt = SMESHUtils::elemSetIterator( moreElemsToConvert ); removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); } @@ -8930,10 +9684,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; @@ -8952,7 +9704,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; @@ -9208,12 +9960,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; } @@ -9271,20 +10023,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()); } } @@ -9352,7 +10092,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; @@ -9363,9 +10103,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); @@ -9373,11 +10113,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 @@ -9386,11 +10130,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++; @@ -9402,21 +10145,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 ); } + } } } @@ -9598,193 +10337,720 @@ 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() { - CrearLastCreated(); - SMESHDS_Mesh* mesh = GetMeshDS(); - - // get an element type and an iterator over elements + bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem ); - 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 ) + for ( int i = 0; i < _nbNodes; ++i ) { - std::vector quantities = - static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities(); - elem = mesh->AddPolyhedralVolume( nodes, quantities ); + if ( _nodes[i] < other._nodes[i] ) return true; + if ( _nodes[i] > other._nodes[i] ) return false; } - else - { - AddElement( nodes, type, elem->IsPoly() ); - elem = 0; // myLastCreatedElems is already filled - } - 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() ); - 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 + size_t NbSub() const + { + return _nodes.size(); + } + + SubBorder Sub(size_t i) const + { + return SubBorder( _nodes[i], NbSub() > 2 ? _nodes[ (i+1)%NbSub() ] : 0 ); + } + + void AddSelfTo( TBorderLinks& borderLinks ) + { + _mappedSubs.resize( NbSub() ); + for ( size_t i = 0; i < NbSub(); ++i ) { - MESSAGE("ChangeElementNodes"); - theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() ); + TBorderLinks::iterator s2b = + borderLinks.insert( std::make_pair( Sub(i), TBorderLinks::mapped_type() )).first; + s2b->second.push_back( this ); + _mappedSubs[ i ] = s2b; } - res = true; - } + } + + void Clear() + { + _nodes.clear(); + } + + 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; + } + + 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; + + 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(); + + return norm; + } + + void ChooseSide() // mark an _elem located at positive side of fissure + { + _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 ); + } + } + + }; // struct FissureBorder + + //-------------------------------------------------------------------------------- + /*! + * \brief Classifier of elements at fissure edge + */ + class FissureNormal + { + 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() ) + { + const SMDS_MeshNode* aCurrNode = static_cast( anIter->next() ); + const SMDS_MeshNode* aNewNode = aCurrNode; + TNodeNodeMap::iterator n2n = theNodeNodeMap.find( aCurrNode ); + if ( n2n != theNodeNodeMap.end() ) + { + aNewNode = n2n->second; + } + else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode )) + { + // duplicate node + aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); + copyPosition( aCurrNode, aNewNode ); + theNodeNodeMap[ aCurrNode ] = aNewNode; + myLastCreatedNodes.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; } @@ -9793,8 +11059,8 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, \brief Creates a hole in a mesh by doubling the nodes of some particular elements \param theNodes - identifiers of nodes to be doubled \param theModifiedElems - identifiers of elements to be updated by the new (doubled) - nodes. If list of element identifiers is empty then nodes are doubled but - they not assigned to elements + 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 */ //================================================================================ @@ -9802,9 +11068,7 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, const std::list< int >& theListOfModifiedElems ) { - MESSAGE("DoubleNodes"); - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + ClearLastCreated(); if ( theListOfNodes.size() == 0 ) return false; @@ -9820,8 +11084,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 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 ); + const SMDS_MeshNode* aNode = aMeshDS->FindNode( *aNodeIter ); if ( !aNode ) continue; @@ -9830,55 +11093,34 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); if ( aNewNode ) { + copyPosition( aNode, aNewNode ); anOldNodeToNewNode[ aNode ] = aNewNode; - myLastCreatedNodes.Append( aNewNode ); + myLastCreatedNodes.push_back( aNewNode ); } } - // Create map of new nodes for modified elements + // Change nodes of elements - std::map< SMDS_MeshElement*, vector > anElemToNodes; + std::vector aNodeArr; std::list< int >::const_iterator anElemIter; - for ( anElemIter = theListOfModifiedElems.begin(); - anElemIter != theListOfModifiedElems.end(); ++anElemIter ) + for ( anElemIter = theListOfModifiedElems.begin(); + anElemIter != theListOfModifiedElems.end(); + anElemIter++ ) { - int aCurr = *anElemIter; - SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr ); + const SMDS_MeshElement* anElem = aMeshDS->FindElement( *anElemIter ); if ( !anElem ) continue; - vector aNodeArr( anElem->NbNodes() ); - - SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); - int ind = 0; - while ( anIter->more() ) + aNodeArr.assign( anElem->begin_nodes(), anElem->end_nodes() ); + for( size_t i = 0; i < aNodeArr.size(); ++i ) { - SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); - if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) - { - const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ]; - aNodeArr[ ind++ ] = aNewNode; - } - else - aNodeArr[ ind++ ] = aCurrNode; + std::map< const SMDS_MeshNode*, const SMDS_MeshNode* >::iterator n2n = + anOldNodeToNewNode.find( aNodeArr[ i ]); + if ( n2n != anOldNodeToNewNode.end() ) + aNodeArr[ i ] = n2n->second; } - anElemToNodes[ anElem ] = aNodeArr; - } - - // Change nodes of elements - - std::map< SMDS_MeshElement*, vector >::iterator - anElemToNodesIter = anElemToNodes.begin(); - for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter ) - { - const SMDS_MeshElement* anElem = anElemToNodesIter->first; - vector aNodeArr = anElemToNodesIter->second; - if ( anElem ) - { - MESSAGE("ChangeElementNodes"); - aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() ); - } + aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], aNodeArr.size() ); } return true; @@ -9888,8 +11130,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 */ //================================================================================ @@ -9899,9 +11141,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); @@ -9931,15 +11172,12 @@ namespace { } void Perform(const gp_Pnt& aPnt, double theTol) { + theTol *= theTol; _state = TopAbs_OUT; _extremum.Perform(aPnt); if ( _extremum.IsDone() ) for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); -#else - _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); -#endif } TopAbs_State State() const { @@ -9950,16 +11188,18 @@ namespace { //================================================================================ /*! - \brief Identify the elements that will be affected by node duplication (actual duplication is not performed. + \brief Identify the elements that will be affected by node duplication (actual duplication is not performed). This method is the first step of DoubleNodeElemGroupsInRegion. \param theElems - list of groups of elements (edges or faces) to be replicated \param theNodesNot - list of groups of nodes not to replicated \param theShape - shape to detect affected elements (element which geometric center - located on or inside shape). + located on or inside shape). If the shape is null, detection is done on faces orientations + (select elements with a gravity center on the side given by faces normals). + This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations. The replicated nodes should be associated to affected elements. - \return groups of affected elements + \return true \sa DoubleNodeElemGroupsInRegion() - */ +*/ //================================================================================ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems, @@ -9968,44 +11208,45 @@ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theEl TIDSortedElemSet& theAffectedElems) { if ( theShape.IsNull() ) - return false; - - const double aTol = Precision::Confusion(); - auto_ptr< BRepClass3d_SolidClassifier> bsc3d; - auto_ptr<_FaceClassifier> aFaceClassifier; - if ( theShape.ShapeType() == TopAbs_SOLID ) { - bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; - bsc3d->PerformInfinitePoint(aTol); - } - else if (theShape.ShapeType() == TopAbs_FACE ) - { - aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + findAffectedElems( theElems, theAffectedElems ); } - - // iterates on indicated elements and get elements by back references from their nodes - TIDSortedElemSet::const_iterator elemItr = theElems.begin(); - for ( ; elemItr != theElems.end(); ++elemItr ) + else { - SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; - if (!anElem) - continue; + const double aTol = Precision::Confusion(); + auto_ptr< BRepClass3d_SolidClassifier> bsc3d; + auto_ptr<_FaceClassifier> aFaceClassifier; + if ( theShape.ShapeType() == TopAbs_SOLID ) + { + bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; + bsc3d->PerformInfinitePoint(aTol); + } + else if (theShape.ShapeType() == TopAbs_FACE ) + { + aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + } - SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); - while ( nodeItr->more() ) + // iterates on indicated elements and get elements by back references from their nodes + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + for ( ; elemItr != theElems.end(); ++elemItr ) { - const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); - if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) - continue; - SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); - while ( backElemItr->more() ) + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) { - const SMDS_MeshElement* curElem = backElemItr->next(); - if ( curElem && theElems.find(curElem) == theElems.end() && - ( bsc3d.get() ? - isInside( curElem, *bsc3d, aTol ) : - isInside( curElem, *aFaceClassifier, aTol ))) - theAffectedElems.insert( curElem ); + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) + { + const SMDS_MeshElement* curElem = backElemItr->next(); + if ( curElem && theElems.find(curElem) == theElems.end() && + ( bsc3d.get() ? + isInside( curElem, *bsc3d, aTol ) : + isInside( curElem, *aFaceClassifier, aTol ))) + theAffectedElems.insert( curElem ); + } } } } @@ -10032,16 +11273,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 @@ -10064,7 +11305,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 ); @@ -10084,16 +11325,17 @@ 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); gp_Vec n1 = vref.Crossed(v1); gp_Vec n2 = vref.Crossed(v2); - return n2.AngleWithRef(n1, vref); + try { + return n2.AngleWithRef(n1, vref); + } + catch ( Standard_Failure ) { + } + return Max( v1.Magnitude(), v2.Magnitude() ); } /*! @@ -10106,22 +11348,25 @@ double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created. * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation). * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples". - * @param theElems - list of groups of volumes, where a group of volume is a set of - * SMDS_MeshElements sorted by Id. - * @param createJointElems - if TRUE, create the elements - * @return TRUE if operation has been completed successfully, FALSE otherwise + * \param theElems - list of groups of volumes, where a group of volume is a set of + * SMDS_MeshElements sorted by Id. + * \param createJointElems - if TRUE, create the elements + * \param onAllBoundaries - if TRUE, the nodes and elements are also created on + * the boundary between \a theDomains and the rest mesh + * \return TRUE if operation has been completed successfully, FALSE otherwise */ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems, - bool createJointElems) + bool createJointElems, + bool onAllBoundaries) { - MESSAGE("----------------------------------------------"); - MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries"); - MESSAGE("----------------------------------------------"); + // MESSAGE("----------------------------------------------"); + // MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries"); + // MESSAGE("----------------------------------------------"); SMESHDS_Mesh *meshDS = this->myMesh->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 @@ -10139,83 +11384,93 @@ 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 { - SMDS_MeshElement* anElem = (SMDS_MeshElement*) *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 (! domain.count(elem)) // neighbor is in another domain : face is shared - { - bool ok = false ; - for (int idombis = 0; idombis < theElems.size(); 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 ) // the characteristics of the face is stored - { - DownIdType face(downIds[n], downTypes[n]); - if (!faceDomains.count(face)) - faceDomains[face] = emptyMap; // create an empty entry for face - 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); - } - } - } + 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; @@ -10224,51 +11479,49 @@ 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); - if (!cellDomains.count(aCell)) - cellDomains[aCell] = emptyMap; // create an empty entry for cell - 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 @@ -10282,188 +11535,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"); - for (int idomain = 0; idomain < theElems.size(); idomain++) + //MESSAGE(".. Duplication of the nodes"); + for (int idomain = idom0; idomain < nbDomains; idomain++) + { + itface = faceDomains.begin(); + for (; itface != faceDomains.end(); ++itface) { - 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()) { - 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; - //MESSAGE("-+-+-a node " << oldId); - if (!nodeDomains.count(oldId)) - nodeDomains[oldId] = emptyMap; // create an empty entry for node - if (nodeDomains[oldId].empty()) - { - nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain - //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain); - } - std::map::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]); - 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]; - for (int ivol=0; ivolfromVtkToSmds(vtkVolIds[ivol]); - SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId); - if (theElems[idom].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) @@ -10475,119 +11732,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) { - 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()); - } + 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); + + 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()); + } - 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()); - } + // --- 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. @@ -10599,38 +11856,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 @@ -10638,43 +11895,51 @@ 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(); + for ( ; name_group != mapOfJunctionGroups.end(); ++name_group ) + { + if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() ) + myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() ); + } meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory - grid->BuildLinks(); + grid->DeleteLinks(); CHRONOSTOP(50); counters::stats(); @@ -10693,9 +11958,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(); @@ -10710,135 +11975,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()); - 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()); - 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 + + 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; + } + + 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 + // --- modify the face - aFace->ChangeNodes(&ln[0], ln.size()); - } + const_cast( aFace )->ChangeNodes( &ln[0], ln.size() ); } + } return true; } @@ -10848,16 +12114,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, @@ -10870,28 +12136,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 @@ -10904,10 +12170,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 @@ -10915,10 +12181,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) @@ -10926,10 +12192,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) @@ -10937,17 +12203,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 @@ -10958,157 +12224,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 @@ -11116,52 +12379,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) @@ -11172,50 +12435,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 @@ -11228,17 +12491,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; @@ -11246,124 +12509,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) @@ -11387,7 +12650,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()) @@ -11395,8 +12659,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)) @@ -11408,22 +12672,27 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() int inode = 0; for ( ; inode < nbFaceNodes; inode += iQuad+1) nodes.push_back(faceNodes[inode]); - if (iQuad) { // add medium nodes + + if (iQuad) // add medium nodes + { for ( inode = 1; inode < nbFaceNodes; inode += 2) nodes.push_back(faceNodes[inode]); if ( nbFaceNodes == 9 ) // bi-quadratic quad nodes.push_back(faceNodes[8]); } // add new face based on volume nodes - if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) { - nbExisted++; - continue; // face already exsist + if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) + { + nbExisted++; // face already exsist + } + else + { + AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 )); + nbCreated++; } - AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 )); - nbCreated++; } } - return ( nbFree==(nbExisted+nbCreated) ); + return ( nbFree == ( nbExisted + nbCreated )); } namespace @@ -11485,45 +12754,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 ); @@ -11567,7 +12850,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 ); @@ -11594,37 +12877,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]; + 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 = @@ -11644,7 +12927,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 ); } } @@ -11652,18 +12935,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 @@ -11674,11 +12957,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 @@ -11686,17 +12969,538 @@ 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; } + +//================================================================================ +/*! + * \brief Copy node position and set \a to node on the same geometry + */ +//================================================================================ + +void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, + const SMDS_MeshNode* to ) +{ + if ( !from || !to ) return; + + SMDS_PositionPtr pos = from->GetPosition(); + if ( !pos || from->getshapeId() < 1 ) return; + + switch ( pos->GetTypeOfPosition() ) + { + case SMDS_TOP_3DSPACE: break; + + case SMDS_TOP_FACE: + { + SMDS_FacePositionPtr fPos = pos; + GetMeshDS()->SetNodeOnFace( to, from->getshapeId(), + fPos->GetUParameter(), fPos->GetVParameter() ); + break; + } + case SMDS_TOP_EDGE: + { + // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!! + SMDS_EdgePositionPtr ePos = pos; + GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() ); + break; + } + case SMDS_TOP_VERTEX: + { + GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() ); + break; + } + case SMDS_TOP_UNSPEC: + default:; + } +} + +namespace // utils for MakePolyLine +{ + //================================================================================ + /*! + * \brief Sequence of found points and a current point data + */ + struct Path + { + std::vector< gp_XYZ > myPoints; + double myLength; + + int mySrcPntInd; //!< start point index + const SMDS_MeshElement* myFace; + SMESH_NodeXYZ myNode1; + SMESH_NodeXYZ myNode2; + int myNodeInd1; + int myNodeInd2; + double myDot1; + double myDot2; + 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 ]; + + // get a cutting plane + + 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] )); + + gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ(); + gp_XYZ plnOrig = p2; + + // find paths connecting the 2 end points of polySeg + + std::vector< Path > paths; paths.reserve(10); + + // initialize paths + + 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.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] ) + { + 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( 0.5 * ( path.myNode1 + path.myNode2 )); + 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 // an end point is at 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(); + } + } + + // extend paths + + 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] )); + + 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; +}