{
int vtkType = this->GetCellType(vtkId);
int cellDim = SMDS_Downward::getCellDimension(vtkType);
- if (cellDim != 3)
- return 0; // TODO voisins des faces ou edges
+ if (cellDim <2)
+ return 0; // TODO voisins des edges = edges connectees
int cellId = this->_cellIdToDownId[vtkId];
int nbCells = _downArray[vtkType]->getNumberOfDownCells(cellId);
const int *downCells = _downArray[vtkType]->getDownCells(cellId);
const unsigned char* downTyp = _downArray[vtkType]->getDownTypes(cellId);
- // --- iteration on faces of the 3D cell.
+ // --- iteration on faces of the 3D cell (or edges on the 2D cell).
int nb = 0;
for (int i = 0; i < nbCells; i++)
const int *upCells = _downArray[cellType]->getUpCells(downId);
const unsigned char* upTypes = _downArray[cellType]->getUpTypes(downId);
- // --- max 2 upCells, one is this cell, the other is a neighbor
+ // ---for a volume, max 2 upCells, one is this cell, the other is a neighbor
+ // for a face, number of neighbors (connected faces) not known
for (int j = 0; j < nbUp; j++)
{
}
}
-/*! Create a volume (prism or hexahedron) by duplication of a face.
- * the nodes of the new face are already created.
+/*! reorder the nodes of a face
* @param vtkVolId vtk id of a volume containing the face, to get an orientation for the face.
- * @param localClonedNodeIds map old node id to new node id.
- * @return vtk id of the new volume.
+ * @param orderedNodes list of nodes to reorder (in out)
+ * @return size of the list
*/
int SMDS_UnstructuredGrid::getOrderedNodesOfFace(int vtkVolId, std::vector<vtkIdType>& orderedNodes)
{
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;
- // --- for each shared face, get the nodes
+ // --- 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;
+ }
+ }
+ }
+ }
+
+ // --- 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);
+ }
}
}
}
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);
+ meshDS->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains);
}
}
// 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 )
{
}
/*! Create a volume (prism or hexahedron) by duplication of a face.
- * the nodes of the new face are already created.
- * @param vtkVolId vtk id of a volume containing the face, to get an orientation for the face.
- * @param localClonedNodeIds map old node id to new node id. The old nodes define the face in the volume.
+ * Designed for use in creation of flat elements separating volume domains.
+ * A face separating two domains is shared by two volume cells.
+ * All the nodes are already created (for the two faces).
+ * Each original Node is associated to corresponding nodes in the domains.
+ * Some nodes may be duplicated for more than two domains, when domain separations intersect.
+ * In that case, even some of the nodes to use for the original face may be changed.
+ * @param vtkVolId: vtk id of a volume containing the face, to get an orientation for the face.
+ * @param domain1: domain of the original face
+ * @param domain2: domain of the duplicated face
+ * @param originalNodes: the vtk node ids of the original face
+ * @param nodeDomains: map(original id --> map(domain --> duplicated node id))
* @return ok if success.
*/
-bool SMESHDS_Mesh::extrudeVolumeFromFace(int vtkVolId, std::map<int,int>& localClonedNodeIds)
+bool SMESHDS_Mesh::extrudeVolumeFromFace(int vtkVolId,
+ int domain1,
+ int domain2,
+ std::set<int>& originalNodes,
+ std::map<int,std::map<int,int> >& nodeDomains)
{
//MESSAGE("extrudeVolumeFromFace " << vtkVolId);
- vector<vtkIdType> orderedNodes;
- orderedNodes.clear();
- map<int, int>::const_iterator it = localClonedNodeIds.begin();
- for (; it != localClonedNodeIds.end(); ++it)
- orderedNodes.push_back(it->first);
+ vector<vtkIdType> orderedOriginals;
+ orderedOriginals.clear();
+ set<int>::const_iterator it = originalNodes.begin();
+ for (; it != originalNodes.end(); ++it)
+ orderedOriginals.push_back(*it);
- int nbNodes = myGrid->getOrderedNodesOfFace(vtkVolId, orderedNodes);
+ int nbNodes = myGrid->getOrderedNodesOfFace(vtkVolId, orderedOriginals);
+ vector<vtkIdType> orderedNodes;
+ for (int i=0; i<nbNodes; i++)
+ orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain1]);
for (int i=0; i<nbNodes; i++)
- orderedNodes.push_back(localClonedNodeIds[orderedNodes[i]]);
+ orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain2]);
SMDS_MeshVolume *vol = this->AddVolumeFromVtkIds(orderedNodes);
// TODO update subshape list of elements and nodes