const int theMethodFlags)
{
// std-like iterator on coordinates of nodes of mesh element
- typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
+ typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
NXyzIterator xyzEnd;
SMDS_VolumeTool volTool;
while ( elemIt->more() )
{
const SMDS_MeshElement* elem = elemIt->next();
+ if(elem->GetType() == SMDSAbs_0DElement)
+ continue;
+
SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
if ( elem->GetType() == SMDSAbs_Volume )
{
const SMDS_MeshNode* closestNode = 0;
list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
for ( ; nIt != nodes.end(); ++nIt ) {
- double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+ double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
if ( minSqDist > sqDist ) {
closestNode = *nIt;
minSqDist = sqDist;
_refCount = 1;
SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
while ( nIt->more() )
- Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+ Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
Enlarge( tolerance );
}
SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
elemSize = 1;
if ( meshInfo.NbNodes() > 2 )
- elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+ elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
}
else
{
_mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
const SMDS_MeshElement* elem = elemIt->next();
SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
- SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+ SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
+ elemSize = 0;
while ( nodeIt->more() )
{
double dist = n1.Distance( cast2Node( nodeIt->next() ));
int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
{
- GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
- SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
+ GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
+ SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
anExtCC.Init( lineCurve, edge);
if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
{
seamLinks.insert( link );
// link direction within the outerFace
- gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
- SMESH_MeshEditor::TNodeXYZ( link.node2()));
+ gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
+ SMESH_TNodeXYZ( link.node2()));
int i1 = outerFace->GetNodeIndex( link.node1() );
int i2 = outerFace->GetNodeIndex( link.node2() );
bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
if ( !closeNode ) return foundElements.size();
- if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+ if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
return foundElements.size(); // to far from any node
if ( type == SMDSAbs_Node )
// get face plane
gp_XYZ fNorm;
if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
- gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+ gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
// perform intersection
IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
while ( nodeIt->more() )
{
const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
- xyz.push_back( TNodeXYZ(node) );
+ xyz.push_back( SMESH_TNodeXYZ(node) );
nodeList.push_back(node);
}
gp_XYZ centerXYZ (0, 0, 0);
SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
while (aNodeItr->more())
- centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
+ centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
theClassifier.Perform(aPnt, theTol);
bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
bool createJointElems)
{
- MESSAGE("------------------------------------------------------");
- MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
- MESSAGE("------------------------------------------------------");
+ MESSAGE("----------------------------------------------");
+ MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+ MESSAGE("----------------------------------------------");
SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
meshDS->BuildDownWardConnectivity(false);
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
// build the list of nodes shared by 2 or more domains, with their domain indexes
- std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
- std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
+ std::map<int,int>celldom; // cell vtkId --> domain
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
+ std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
faceDomains.clear();
+ celldom.clear();
+ cellDomains.clear();
nodeDomains.clear();
std::map<int,int> emptyMap;
emptyMap.clear();
if (!faceDomains[face].count(idom))
{
faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+ celldom[vtkId] = idom;
}
}
}
}
MESSAGE("Number of shared faces " << faceDomains.size());
+ std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
+
+ // --- explore the shared faces domain by domain,
+ // explore the nodes of the face and see if they belong to a cell in the domain,
+ // which has only a node or an edge on the border (not a shared face)
+
+ for (int idomain = 0; idomain < theElems.size(); idomain++)
+ {
+ const TIDSortedElemSet& domain = theElems[idomain];
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
+ {
+ std::map<int, int> domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (; itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ //MESSAGE(" node " << oldId);
+ std::set<int> cells;
+ cells.clear();
+ vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+ for (int i=0; i<l.ncells; i++)
+ {
+ int vtkId = l.cells[i];
+ const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
+ if (!domain.count(anElem))
+ continue;
+ int vtkType = grid->GetCellType(vtkId);
+ int downId = grid->CellIdToDownId(vtkId);
+ DownIdType aCell(downId, vtkType);
+ if (celldom.count(vtkId))
+ continue;
+ cellDomains[aCell][idomain] = vtkId;
+ celldom[vtkId] = idomain;
+ }
+ }
+ }
+ }
- // --- for each shared face, get the nodes
+ // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
+ // for each shared face, get the nodes
// for each node, for each domain of the face, create a clone of the node
- std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
- for( ; itface != faceDomains.end();++itface )
+ for (int idomain = 0; idomain < theElems.size(); idomain++)
{
- DownIdType face = itface->first;
- std::map<int,int> domvol = itface->second;
- std::set<int> oldNodes;
- oldNodes.clear();
- grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- std::set<int>::iterator itn = oldNodes.begin();
- for (;itn != oldNodes.end(); ++itn)
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
{
- int oldId = *itn;
- if (!nodeDomains.count(oldId))
- nodeDomains[oldId] = emptyMap; // create an empty entry for node
- std::map<int,int>::iterator itdom = domvol.begin();
- for(; itdom != domvol.end(); ++itdom)
+ std::map<int, int> domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (; itn != oldNodes.end(); ++itn)
{
- int idom = itdom->first;
- if ( nodeDomains[oldId].empty() )
- nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
- else
+ int oldId = *itn;
+ //MESSAGE(" node " << oldId);
+ if (!nodeDomains.count(oldId))
+ nodeDomains[oldId] = emptyMap; // create an empty entry for node
+ if (nodeDomains[oldId].empty())
+ nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
+ std::map<int, int>::iterator itdom = domvol.begin();
+ for (; itdom != domvol.end(); ++itdom)
{
- double *coords = grid->GetPoint(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
+ int idom = itdom->first;
+ //MESSAGE(" domain " << idom);
+ if (!nodeDomains[oldId].count(idom))
+ {
+ double *coords = grid->GetPoint(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);
+ }
}
}
}
// get node id's of the face (id SMDS = id VTK)
// create flat element with old and new nodes if requested
+ // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
+ // (domain1 X domain2) = domain1 + MAXINT*domain2
+ std::map<int, std::map<long,int> > nodeQuadDomains;
+
if (createJointElems)
{
itface = faceDomains.begin();
std::set<int>::iterator itn;
oldNodes.clear();
grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- std::map<int,int> localClonedNodeIds;
std::map<int,int> domvol = itface->second;
std::map<int,int>::iterator itdom = domvol.begin();
int vtkVolId = itdom->second;
itdom++;
int dom2 = itdom->first;
-
- localClonedNodeIds.clear();
- for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
- {
- int oldId = *itn;
- int refid = oldId;
- if (nodeDomains[oldId].count(dom1))
- refid = nodeDomains[oldId][dom1];
- else
- MESSAGE("--- problem domain node " << dom1 << " " << oldId);
- int newid = oldId;
- if (nodeDomains[oldId].count(dom2))
- newid = nodeDomains[oldId][dom2];
- else
- MESSAGE("--- problem domain node " << dom2 << " " << oldId);
- localClonedNodeIds[oldId] = newid;
- }
- meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
+ grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, nodeQuadDomains);
}
}
// get node id's of the face
// replace old nodes by new nodes in volumes, and update inverse connectivity
+ MESSAGE("cellDomains " << cellDomains.size());
+ faceDomains.insert(cellDomains.begin(), cellDomains.end());
itface = faceDomains.begin();
for( ; itface != faceDomains.end();++itface )
{
* \param toCopyElements - if true, the checked elements will be copied into the targetMesh
* \param toCopyExistingBondary - if true, not only new but also pre-existing
* boundary elements will be copied into the targetMesh
+ * \param toAddExistingBondary - if true, not only new but also pre-existing
+ * boundary elements will be added into the new group
+ * \param aroundElements - if true, elements will be created on boundary of given
+ * elements else, on boundary of the whole mesh. This
+ * option works for 2D elements only.
+ * \return nb of added boundary elements
*/
//================================================================================
-void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
- Bnd_Dimension dimension,
- SMESH_Group* group/*=0*/,
- SMESH_Mesh* targetMesh/*=0*/,
- bool toCopyElements/*=false*/,
- bool toCopyExistingBondary/*=false*/)
+int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
+ Bnd_Dimension dimension,
+ SMESH_Group* group/*=0*/,
+ SMESH_Mesh* targetMesh/*=0*/,
+ bool toCopyElements/*=false*/,
+ bool toCopyExistingBondary/*=false*/,
+ bool toAddExistingBondary/*= false*/,
+ bool aroundElements/*= false*/)
{
SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
throw SALOME_Exception(LOCALIZED("wrong element type"));
+ if ( aroundElements && elemType == SMDSAbs_Volume )
+ throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
+
if ( !targetMesh )
toCopyElements = toCopyExistingBondary = false;
SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
+ int nbAddedBnd = 0;
+
+ // editor adding present bnd elements and optionally holding elements to add to the group
+ SMESH_MeshEditor* presentEditor;
+ SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
+ presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
SMDS_VolumeTool vTool;
- TIDSortedElemSet emptySet, avoidSet;
+ TIDSortedElemSet avoidSet;
+ const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
int inode;
typedef vector<const SMDS_MeshNode*> TConnectivity;
const SMDS_MeshElement* elem = eIt->next();
const int iQuad = elem->IsQuadratic();
+ // ------------------------------------------------------------------------------------
// 1. For an elem, get present bnd elements and connectivities of missing bnd elements
+ // ------------------------------------------------------------------------------------
vector<const SMDS_MeshElement*> presentBndElems;
vector<TConnectivity> missingBndElems;
TConnectivity nodes;
{
nodes[0] = elem->GetNode(i);
nodes[1] = elem->GetNode((i+1)%nbNodes);
- if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
+ if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
continue; // not free link
//if ( iQuad )
}
}
+ // ---------------------------------
// 2. Add missing boundary elements
+ // ---------------------------------
if ( targetMesh != myMesh )
// instead of making a map of nodes in this mesh and targetMesh,
// we create nodes with same IDs. We can renumber them later, if needed
TConnectivity nodes( srcNodes.size() );
for ( inode = 0; inode < nodes.size(); ++inode )
nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
+ if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+ missType,
+ /*noMedium=*/true))
+ continue;
tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+ ++nbAddedBnd;
}
else
for ( int i = 0; i < missingBndElems.size(); ++i )
{
- TConnectivity& nodes = missingBndElems[i];
+ TConnectivity& nodes = missingBndElems[i];
+ if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+ missType,
+ /*noMedium=*/true))
+ continue;
tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+ ++nbAddedBnd;
}
+ // ----------------------------------
// 3. Copy present boundary elements
+ // ----------------------------------
if ( toCopyExistingBondary )
for ( int i = 0 ; i < presentBndElems.size(); ++i )
{
TConnectivity nodes( e->NbNodes() );
for ( inode = 0; inode < nodes.size(); ++inode )
nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
- tgtEditor.AddElement(nodes, missType, e->IsPoly());
- // leave only missing elements in tgtEditor.myLastCreatedElems
- tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
+ presentEditor->AddElement(nodes, missType, e->IsPoly());
+ }
+ else // store present elements to add them to a group
+ for ( int i = 0 ; i < presentBndElems.size(); ++i )
+ {
+ presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
}
+
} // loop on given elements
- // 4. Fill group with missing boundary elements
+ // ---------------------------------------------
+ // 4. Fill group with boundary elements
+ // ---------------------------------------------
if ( group )
{
if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
}
tgtEditor.myLastCreatedElems.Clear();
+ tgtEditor2.myLastCreatedElems.Clear();
+ // -----------------------
// 5. Copy given elements
- if ( toCopyElements )
+ // -----------------------
+ if ( toCopyElements && targetMesh != myMesh )
{
if (elements.empty())
eIt = aMesh->elementsIterator(elemType);
tgtEditor.myLastCreatedElems.Clear();
}
}
- return;
+ return nbAddedBnd;
}