X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=db8f8a36d91b9535fb675074688e1a9c8fb46c99;hb=621f26055ecc20aa9c81784b71aae10c2ab4a9b7;hp=9d35151af54ecb1e4751a30c584876f9e2215611;hpb=fcae5eda64fe8a9a60b290c7ccd0039fb7c44abe;p=modules%2Fsmesh.git diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 9d35151af..db8f8a36d 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -94,6 +94,8 @@ #include #include #include +#include +#include #define cast2Node(elem) static_cast( elem ) @@ -363,45 +365,55 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) if ( aMesh->ShapeToMesh().IsNull() ) return 0; - if ( theElem->GetType() == SMDSAbs_Node ) - { - int aShapeID = theElem->getshapeId(); - if (aShapeID <= 0) - return 0; - else - return aShapeID; - } - - TopoDS_Shape aShape; // the shape a node is on - SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - int aShapeID = node->getshapeId(); - if (aShapeID > 0) { - SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ); - if ( sm ) { - if ( sm->Contains( theElem )) - return aShapeID; - if ( aShape.IsNull() ) - aShape = aMesh->IndexToShape( aShapeID ); - } - else { - //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID ); + int aShapeID = theElem->getshapeId(); + if ( aShapeID < 1 ) + return 0; + + if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID )) + if ( sm->Contains( theElem )) + return aShapeID; + + if ( theElem->GetType() == SMDSAbs_Node ) { + MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() ); + } + else { + MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() ); + } + + TopoDS_Shape aShape; // the shape a node of theElem is on + if ( theElem->GetType() != SMDSAbs_Node ) + { + SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + if ((aShapeID = node->getshapeId()) > 0) { + if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) { + if ( sm->Contains( theElem )) + return aShapeID; + if ( aShape.IsNull() ) + aShape = aMesh->IndexToShape( aShapeID ); + } } } } // None of nodes is on a proper shape, // find the shape among ancestors of aShape on which a node is - if ( aShape.IsNull() ) { - //MESSAGE ("::FindShape() - NONE node is on shape") - return 0; + if ( !aShape.IsNull() ) { + TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape )); + for ( ; ancIt.More(); ancIt.Next() ) { + SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() ); + if ( sm && sm->Contains( theElem )) + return aMesh->ShapeToIndex( ancIt.Value() ); + } } - TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape )); - for ( ; ancIt.More(); ancIt.Next() ) { - SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() ); - if ( sm && sm->Contains( theElem )) - return aMesh->ShapeToIndex( ancIt.Value() ); + 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; } //MESSAGE ("::FindShape() - SHAPE NOT FOUND") @@ -5306,7 +5318,7 @@ void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, * \param theCopy - if true, create translated copies of theElems * \param theMakeGroups - if true and theCopy, create translated groups * \param theTargetMesh - mesh to copy translated elements into - * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups + * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups */ //================================================================================ @@ -9183,7 +9195,7 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode //======================================================================= /*! * \brief Convert elements contained in a submesh to quadratic - * \retval int - nb of checked elements + * \return int - nb of checked elements */ //======================================================================= @@ -9203,8 +9215,6 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, if( !elem || elem->IsQuadratic() ) continue; int id = elem->GetID(); - //MESSAGE("elem " << id); - id = 0; // get a free number for new elements int nbNodes = elem->NbNodes(); SMDSAbs_ElementType aType = elem->GetType(); @@ -9212,6 +9222,8 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, if ( elem->GetEntityType() == SMDSEntity_Polyhedra ) nbNodeInFaces = static_cast( elem )->GetQuantities(); + GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); + const SMDS_MeshElement* NewElem = 0; switch( aType ) @@ -9265,8 +9277,6 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, ReplaceElemInGroups( elem, NewElem, GetMeshDS()); if( NewElem ) theSm->AddElement( NewElem ); - - GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); } // if (!GetMeshDS()->isCompacted()) // GetMeshDS()->compactMesh(); @@ -9392,14 +9402,152 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh aHelper.FixQuadraticElements(); } - if (!GetMeshDS()->isCompacted()) - GetMeshDS()->compactMesh(); +} + +//================================================================================ +/*! + * \brief Makes given elements quadratic + * \param theForce3d - if true, the medium nodes will be placed in the middle of link + * \param theElements - elements to make quadratic + */ +//================================================================================ + +void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, + TIDSortedElemSet& theElements) +{ + if ( theElements.empty() ) return; + + // we believe that all theElements are of the same type + SMDSAbs_ElementType elemType = (*theElements.begin())->GetType(); + + // get all nodes shared by theElements + TIDSortedNodeSet allNodes; + TIDSortedElemSet::iterator eIt = theElements.begin(); + for ( ; eIt != theElements.end(); ++eIt ) + allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() ); + + // complete theElements with elements of lower dim whose all nodes are in allNodes + + TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements + TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ]; + TIDSortedNodeSet::iterator nIt = allNodes.begin(); + for ( ; nIt != allNodes.end(); ++nIt ) + { + const SMDS_MeshNode* n = *nIt; + SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(); + while ( invIt->more() ) + { + const SMDS_MeshElement* e = invIt->next(); + if ( e->IsQuadratic() ) + { + quadAdjacentElems[ e->GetType() ].insert( e ); + continue; + } + if ( e->GetType() >= elemType ) + { + continue; // same type of more complex linear element + } + + if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second ) + continue; // e is already checked + + // check nodes + bool allIn = true; + SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + while ( nodeIt->more() && allIn ) + allIn = allNodes.count( cast2Node( nodeIt->next() )); + if ( allIn ) + theElements.insert(e ); + } + } + + SMESH_MesherHelper helper(*myMesh); + helper.SetIsQuadratic( true ); + + // add links of quadratic adjacent elements to the helper + + if ( !quadAdjacentElems[SMDSAbs_Edge].empty() ) + for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin(); + eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt ) + { + helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) ); + } + if ( !quadAdjacentElems[SMDSAbs_Face].empty() ) + for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin(); + eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt ) + { + helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) ); + } + if ( !quadAdjacentElems[SMDSAbs_Volume].empty() ) + for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin(); + eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt ) + { + helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) ); + } + + // make quadratic elements instead of linear ones + + SMESHDS_Mesh* meshDS = GetMeshDS(); + SMESHDS_SubMesh* smDS = 0; + for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt ) + { + const SMDS_MeshElement* elem = *eIt; + if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() ) + continue; + + int id = elem->GetID(); + SMDSAbs_ElementType type = elem->GetType(); + vector nodes ( elem->begin_nodes(), elem->end_nodes()); + + if ( !smDS || !smDS->Contains( elem )) + smDS = meshDS->MeshElements( elem->getshapeId() ); + meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false); + + SMDS_MeshElement * newElem = 0; + switch( nodes.size() ) + { + case 4: // cases for most multiple element types go first (for optimization) + if ( type == SMDSAbs_Volume ) + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + else + newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + case 8: + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + break; + case 3: + newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d); + break; + case 2: + newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d); + break; + case 5: + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], id, theForce3d); + break; + case 6: + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], id, theForce3d); + break; + default:; + } + ReplaceElemInGroups( elem, newElem, meshDS); + if( newElem && smDS ) + smDS->AddElement( newElem ); + } + + if ( !theForce3d && !getenv("NO_FixQuadraticElements")) + { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion + helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh + helper.FixQuadraticElements(); + } } //======================================================================= /*! * \brief Convert quadratic elements to linear ones and remove quadratic nodes - * \retval int - nb of checked elements + * \return int - nb of checked elements */ //======================================================================= @@ -9409,7 +9557,6 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int nbElem = 0; SMESHDS_Mesh* meshDS = GetMeshDS(); - const bool notFromGroups = false; while( theItr->more() ) { @@ -9417,44 +9564,28 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, nbElem++; if( elem && elem->IsQuadratic()) { - int id = elem->GetID(); - int nbNodes = elem->NbNodes(); - vector nodes, mediumNodes; - nodes.reserve( nbNodes ); - mediumNodes.reserve( nbNodes ); - - for(int i = 0; i < nbNodes; i++) - { - const SMDS_MeshNode* n = elem->GetNode(i); - - if( elem->IsMediumNode( n ) ) - mediumNodes.push_back( n ); - else - nodes.push_back( n ); - } - if( nodes.empty() ) continue; + int id = elem->GetID(); + int nbCornerNodes = elem->NbCornerNodes(); SMDSAbs_ElementType aType = elem->GetType(); - //remove old quadratic element - meshDS->RemoveFreeElement( elem, theSm, notFromGroups ); + vector nodes( elem->begin_nodes(), elem->end_nodes() ); - SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id ); - ReplaceElemInGroups(elem, NewElem, meshDS); - if( theSm && NewElem ) - theSm->AddElement( NewElem ); + //remove a quadratic element + if ( !theSm || !theSm->Contains( elem )) + theSm = meshDS->MeshElements( elem->getshapeId() ); + meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false ); // remove medium nodes - vector::iterator nIt = mediumNodes.begin(); - for ( ; nIt != mediumNodes.end(); ++nIt ) { - const SMDS_MeshNode* n = *nIt; - if ( n->NbInverseElements() == 0 ) { - if ( n->getshapeId() != theShapeID ) - meshDS->RemoveFreeNode( n, meshDS->MeshElements - ( n->getshapeId() )); - else - meshDS->RemoveFreeNode( n, theSm ); - } - } + for ( unsigned 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 ); + ReplaceElemInGroups(elem, newElem, meshDS); + if( theSm && newElem ) + theSm->AddElement( newElem ); } } return nbElem; @@ -9464,7 +9595,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, //function : ConvertFromQuadratic //purpose : //======================================================================= -bool SMESH_MeshEditor::ConvertFromQuadratic() + +bool SMESH_MeshEditor::ConvertFromQuadratic() { int nbCheckedElems = 0; if ( myMesh->HasShapeToMesh() ) @@ -9491,6 +9623,102 @@ bool SMESH_MeshEditor::ConvertFromQuadratic() return true; } +namespace +{ + //================================================================================ + /*! + * \brief Return true if all medium nodes of the element are in the node set + */ + //================================================================================ + + bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet ) + { + for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i ) + if ( !nodeSet.count( elem->GetNode(i) )) + return false; + return true; + } +} + +//================================================================================ +/*! + * \brief Makes given elements linear + */ +//================================================================================ + +void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) +{ + if ( theElements.empty() ) return; + + // collect IDs of medium nodes of theElements; some of these nodes will be removed + set mediumNodeIDs; + TIDSortedElemSet::iterator eIt = theElements.begin(); + for ( ; eIt != theElements.end(); ++eIt ) + { + const SMDS_MeshElement* e = *eIt; + for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i ) + mediumNodeIDs.insert( e->GetNode(i)->GetID() ); + } + + // replace given elements by linear ones + typedef SMDS_SetIterator TSetIterator; + SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() )); + removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); + + // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs + // except those elements sharing medium nodes of quadratic element whose medium nodes + // are not all in mediumNodeIDs + + // get remaining medium nodes + TIDSortedNodeSet mediumNodes; + set::iterator nIdsIt = mediumNodeIDs.begin(); + for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt ) + if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt )) + mediumNodes.insert( mediumNodes.end(), n ); + + // find more quadratic elements to convert + TIDSortedElemSet moreElemsToConvert; + TIDSortedNodeSet::iterator nIt = mediumNodes.begin(); + for ( ; nIt != mediumNodes.end(); ++nIt ) + { + SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator(); + while ( invIt->more() ) + { + const SMDS_MeshElement* e = invIt->next(); + if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes )) + { + // find a more complex element including e and + // whose medium nodes are not in mediumNodes + bool complexFound = false; + for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type ) + { + SMDS_ElemIteratorPtr invIt2 = + (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type )); + while ( invIt2->more() ) + { + const SMDS_MeshElement* eComplex = invIt2->next(); + if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes)) + { + int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size(); + if ( nbCommonNodes == e->NbNodes()) + { + complexFound = true; + type = SMDSAbs_NbElementTypes; // to quit from the outer loop + break; + } + } + } + } + if ( !complexFound ) + moreElemsToConvert.insert( e ); + } + } + } + elemIt = SMDS_ElemIteratorPtr + (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() )); + removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); +} + //======================================================================= //function : SewSideElements //purpose : @@ -10120,7 +10348,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1 * \param nReplaceMap - output map of corresponding nodes - * \retval bool - is a success or not + * \return bool - is a success or not */ //================================================================================ @@ -10602,12 +10830,35 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, return DoubleNodes( theElems, theNodesNot, anAffected ); } +/*! + * \brief compute an oriented angle between two planes defined by four points. + * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2) + * @param p0 base of the rotation axe + * @param p1 extremity of the rotation axe + * @param g1 belongs to the first plane + * @param g2 belongs to the second plane + */ +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); +} + /*! * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. * The list of groups must describe a partition of the mesh volumes. * The nodes of the internal faces at the boundaries of the groups are doubled. * In option, the internal faces are replaced by flat elements. * Triangles are transformed in prisms, and quadrangles in hexahedrons. + * The flat elements are stored in groups of volumes. * @param theElems - list of groups of volumes, where a group of volume is a set of * SMDS_MeshElements sorted by Id. * @param createJointElems - if TRUE, create the elements @@ -10621,7 +10872,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectormyMesh->GetMeshDS(); - meshDS->BuildDownWardConnectivity(false); + meshDS->BuildDownWardConnectivity(true); CHRONO(50); SMDS_UnstructuredGrid *grid = meshDS->getGrid(); @@ -10638,6 +10889,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector emptyMap; + std::set emptySet; emptyMap.clear(); for (int idom = 0; idom < theElems.size(); idom++) @@ -10679,7 +10931,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector, DownIdCompare>::iterator itface; // --- explore the shared faces domain by domain, @@ -10730,6 +10982,13 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector, std::vector > edgesMultiDomains; // nodes of edge --> ordered domains + std::map > mutipleNodes; // nodes muti domains with domain order + for (int idomain = 0; idomain < theElems.size(); idomain++) { itface = faceDomains.begin(); @@ -10743,6 +11002,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector oldNodes; oldNodes.clear(); grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + bool isMultipleDetected = false; std::set::iterator itn = oldNodes.begin(); for (; itn != oldNodes.end(); ++itn) { @@ -10757,13 +11017,112 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorfirst; //MESSAGE(" domain " << idom); - if (!nodeDomains[oldId].count(idom)) + if (!nodeDomains[oldId].count(idom)) // --- node to clone { + if (nodeDomains[oldId].size() >= 2) // a multiple node + { + vector orderedDoms; + //MESSAGE("multiple node " << oldId); + isMultipleDetected =true; + 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(" newNode " << newId); + //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <first.cellId; + unsigned char cellType = itface->first.cellType; + 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])) + { + vector vn0 = mutipleNodes[nodes[0]]; + vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; + sort( vn0.begin(), vn0.end() ); + sort( vn1.begin(), vn1.end() ); + if (vn0 == vn1) + { + //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 < vn0.size(); id++) + { + int idom = vn0[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 + } } } } @@ -10778,11 +11137,12 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector > nodeQuadDomains; + std::map mapOfJunctionGroups; if (createJointElems) { itface = faceDomains.begin(); - for( ; itface != faceDomains.end();++itface ) + for (; itface != faceDomains.end(); ++itface) { DownIdType face = itface->first; std::set oldNodes; @@ -10790,13 +11150,68 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorGetNodeIds(oldNodes, face.cellId, face.cellType); - std::map domvol = itface->second; - std::map::iterator itdom = domvol.begin(); + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); int dom1 = itdom->first; int vtkVolId = itdom->second; itdom++; int dom2 = itdom->first; - grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, nodeQuadDomains); + SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, + nodeQuadDomains); + stringstream grpname; + grpname << "j_"; + if (dom1 < dom2) + grpname << dom1 << "_" << dom2; + else + grpname << dom2 << "_" << dom1; + 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()); + } + } + + // --- create volumes on multiple domain intersection if requested + // iterate on edgesMultiDomains + + if (createJointElems) + { + 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); + + stringstream grpname; + grpname << "mj_"; + grpname << 0 << "_" << 0; + 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()); + } + else + { + // TODO quadratic nodes + } } } @@ -10881,6 +11296,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorCleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory grid->BuildLinks(); CHRONOSTOP(50); @@ -10888,6 +11304,167 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems) +{ + MESSAGE("-------------------------------------------------"); + MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups"); + MESSAGE("-------------------------------------------------"); + + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + + // --- For each group of faces + // duplicate the nodes, create a flat element based on the face + // replace the nodes of the faces by their clones + + std::map clonedNodes; + std::map intermediateNodes; + clonedNodes.clear(); + intermediateNodes.clear(); + std::map mapOfJunctionGroups; + mapOfJunctionGroups.clear(); + + for (int idom = 0; idom < theElems.size(); idom++) + { + 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_MeshNode* clone = 0; + if (!clonedNodes.count(node)) + { + clone = meshDS->AddNode(node->X(), node->Y(), node->Z()); + clonedNodes[node] = clone; + } + else + clone = clonedNodes[node]; + + if (isMedium) + ln3.push_back(clone); + else + ln1.push_back(clone); + + 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); + } + } + + // --- 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 + + aFace->ChangeNodes(&ln[0], ln.size()); + } + } + return true; +} + //================================================================================ /*! * \brief Generates skin mesh (containing 2D cells) from 3D mesh